Close

Интеграция Concourse-CI и Atlassian Open DevOps

Многие команды развертывают собственные инструменты, отвечающие их потребностям, или годами используют устаревшие решения. И для этих незаменимых в процессе разработки инструментов нет готовых интеграций с Jira. К счастью, в таком случае можно без труда создать собственную интеграцию с помощью API REST от Atlassian, описанных в документации по разработке приложений для Cloud на странице сообщества разработчиков Atlassian. Concourse-CI — это продукт CI/CD, для которого на момент написания статьи нет интеграции в Atlassian Marketplace. Здесь мы расскажем, как создать базовую интеграцию между Concourse-CI и Jira с помощью API REST от Atlassian.

Обязательные условия

Воспользуйтесь необходимой документацией для настройки Docker, Docker Compose и Concourse-CI. Concourse-CI запускается в Docker и позволяет использовать скрипт Docker Compose, с которым проще начать работу.

Прочитайте о демонстрационном приложении Atlassian ImageLabeller по этой ссылке. Здесь мы покажем, как с помощью Concourse-CI развернуть SubmitImage, компонент приложения ImageLabeller, на AWS.

Docker

Настройте Docker и Docker Compose, следуя инструкциям из соответствующей документации по продукту:

Docker: https://docs.docker.com/get-docker/
Docker Compose: https://docs.docker.com/compose/install/

Concourse-CI

После установки Docker и Docker Compose можно запустить Concourse-CI из предоставленного файла docker-compose.yml.

Выполните действия из краткого руководства по началу работы с Concourse-CI: https://concourse-ci.org/quick-start.html#docker-compose-concourse. Вам нужно будет безопасно передать в Concourse-CI учетные данные, для чего в руководстве предлагается использовать интеграцию Concourse-CI с AWS Secrets Manager.

Интеграция Concourse-CI с AWS Secrets Manager

В этой документации описано, как интегрировать Concourse-CI с AWS Secrets Manager. Следуйте инструкциям, чтобы настроить интеграцию и начать работу.

Чтобы интеграция заработала, файл docker-compose.yml, используемый для запуска Concourse-CI, нужно слегка изменить. Добавьте в файл docker-compose.yml, предоставленный в Concourse-CI по умолчанию, переменные
CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY, CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY и CONCOURSE_AWS_SECRETSMANAGER_REGION.

version: '3'

services:
  concourse-db:
    image: postgres
    environment:
      POSTGRES_DB: concourse
      POSTGRES_PASSWORD: concourse_pass
      POSTGRES_USER: concourse_user
      PGDATA: /database

  concourse:
    image: concourse/concourse
    command: quickstart
    privileged: true
    depends_on: [concourse-db]
    ports: ["8080:8080"]
    environment:
      CONCOURSE_POSTGRES_HOST: concourse-db
      CONCOURSE_POSTGRES_USER: concourse_user
      CONCOURSE_POSTGRES_PASSWORD: concourse_pass
      CONCOURSE_POSTGRES_DATABASE: concourse
      CONCOURSE_EXTERNAL_URL: http://localhost:8080
      CONCOURSE_ADD_LOCAL_USER: test:test
      CONCOURSE_MAIN_TEAM_LOCAL_USER: test
      # instead of relying on the default "detect"
      CONCOURSE_WORKER_BAGGAGECLAIM_DRIVER: overlay
      CONCOURSE_CLIENT_SECRET: Y29uY291cnNlLXdlYgo=
      CONCOURSE_TSA_CLIENT_SECRET: Y29uY291cnNlLXdvcmtlcgo=
      CONCOURSE_X_FRAME_OPTIONS: allow
      CONCOURSE_CONTENT_SECURITY_POLICY: "*"
      CONCOURSE_CLUSTER_NAME: tutorial
      CONCOURSE_WORKER_CONTAINERD_DNS_SERVER: "8.8.8.8"
      CONCOURSE_WORKER_RUNTIME: "containerd"
      CONCOURSE_ENABLE_ACROSS_STEP: "true"
      CONCOURSE_ENABLE_PIPELINE_INSTANCES: "true"
      CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY: <add access key>
      CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY: <add secret key>
      CONCOURSE_AWS_SECRETSMANAGER_REGION: <add a region>

После настройки интеграции включите ее и запустите Concourse-CI, а затем добавьте в AWS Secrets Manager следующие секреты:

/concourse/main/bitbucket_username

/concourse/main/bitbucket_api_key

/concourse/main/bitbucket_ssh_key

/concourse/main/docker_username

/concourse/main/docker_api_key

/concourse/main/AWS_ACCESS_KEY_ID

/concourse/main/AWS_SECRET_ACCESS_KEY

/concourse/main/AWS_DEFAULT_REGION

Если вы не используете Bitbucket для работы с кодом, а JFrog — в качестве репозитория Docker, возможно, секреты Bitbucket и Docker придется заменить. В качестве упражнения предлагаем вам самостоятельно добавить нужные секреты с учетом используемых инструментов.

Секреты Bitbucket и Docker

Работа с Concourse-CI

Запустите команду docker ps -a до и после выполнения команды docker-compose up -d, чтобы убедиться в корректной работе Concourse-CI.

docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

docker-compose up -d
Creating network "restapiproject_default" with the default driver
Creating restapiproject_concourse-db_1 ... done
Creating restapiproject_concourse_1    ... done

docker ps -a
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                    NAMES
bd2b5afd0ac7   concourse/concourse   "dumb-init /usr/loca…"   3 seconds ago   Up 2 seconds   0.0.0.0:8080->8080/tcp   restapiproject_concourse_1
bd9005b45636   postgres              "docker-entrypoint.s…"   3 seconds ago   Up 2 seconds   5432/tcp                 restapiproject_concourse-db_1

После выполнения команды fly -t tutorial login -c http://localhost:8080 -u test -p test перейдите по адресу http://localhost:8080/.

fly -t tutorial login -c http://localhost:8080 -u test -p test
logging in to team 'main'
target saved

Конвейеры пока не определены.

Конвейер Hello World

Выполните инструкции по настройке конвейера Hellow World из документации Concourse-CI: https://concourse-ci.org/tutorial-hello-world.html. Это нужно для знакомства с инструментом fly CLI и для того, чтобы научиться работать с Concourse-CI из командной строки.

В следующем разделе показано, как развернуть функцию AWS Lambda, написанную на языке Golang, в одном регионе AWS с помощью Concourse-CI и создать обновление для задачи Jira в рамках этого процесса.

Развертывание SubmitImage с помощью Concourse-CI

Развертывание функции Lambda для репозитория SubmitImage с помощью Concourse-CI выполняется в три этапа. Первый: написать простой bash-скрипт, использующий API REST Jira Cloud для составления комментария к задаче Jira. Это простейшая из возможных интеграций. Второй: создать образ Docker с инструментами, необходимыми для разработки и развертывания функции AWS Lambda на Golang. И наконец, третий: написать пару конфигурационных файлов Concourse-CI. Первый из них, parent.yml, будет отслеживать в репозитории SubmitImage появление новых веток и запускать новые конвейеры для развертывания коммитов из этих веток. Другой файл, child.yml, будет определять необходимый набор действий для развертывания изменения.

Этап 1. Обновление задач Jira через API REST

Этот скрипт обновления задействует API REST платформы Jira Cloud, чтобы создать комментарий к конкретной задаче Jira. Существует пять обязательных параметров, которые необходимо задавать при каждом запуске скрипта. Параметры jiraUsername, jiraApiToken и рабочее пространство, как правило, одинаковы при каждом запуске того или иного конвейера, а параметр issueKey зависит от имени конкретной развертываемой ветки. При работе над задачей Jira рекомендуется указывать ее идентификатор в именах веток и комментариях к коммитам. В этой статье предполагается, что вы соблюдаете это пожелание и имена веток совпадают с идентификатором задачи Jira.

Как найти параметры
Имя пользователя Jira


Имя пользователя Jira представляет собой адрес электронной почты, используемый для входа в Jira.

Токен API Jira
Перейдите в раздел Account Settings (Настройки аккаунта).

Токены API Jira: раздел Account Settings (Настройки аккаунта)

Нажмите Security (Безопасность).

Раздел Security (Безопасность) в аккаунте

Нажмите Create and manage API tokens (Создание токенов API и управление ими)

Рабочее пространство

В URL-адресе экземпляра Jira https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 часть pmmquickstartguide01 является названием рабочего пространства.

Ключ задачи

В URL-адресе задачи Jira https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 часть IM-203 является ключом задачи. Добавляйте идентификатор задачи Jira в комментарии к коммитам и имена веток, чтобы интеграция записывала обновления в нужное место.

Комментарий

Комментарий может быть любым.

Скрипт обновления

Скрипт обновления представляет собой простой bash-скрипт, использующий конечную точку API REST комментария к задаче Jira. Документацию по вызову API см. здесь. Для более тесной интеграции скрипт можно изменить, используя предоставленный шаблон для дополнительных вызовов API. Скопируйте скрипт в файл под названием concourse-ci-integration.sh и поместите этот файл в репозиторий updateScript в Bitbucket или GitHub.

#!/usr/bin/env bash

addCommentToIssue() {
  printf "addCommentToIssue\n"

  local jiraUsername=$1
  shift
  local jiraApiToken=$1
  shift
  local workspace=$1
  shift
  local issueKey=$1
  shift
  local comment=$1
  shift

  curl -s --request POST \
  --url 'https://'"${workspace}"'.atlassian.net/rest/api/3/issue/'"${issueKey}"'/comment' \
  --user "${jiraUsername}"':'"${jiraApiToken}" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "body": {
      "type": "doc",
      "version": 1,
      "content": [{
        "type": "paragraph",
        "content": [{
          "text": "'"${comment}"'",
          "type": "text"
        }]
      }]
    }
  }' | jq
}

main() {
  printf "main\n"

  while getopts ":c:k:o:u:t:w:" opt; do
    case $opt in
    c)
      local comment=$OPTARG
      ;;
    k)
      local issueKey=$OPTARG
      ;;
    o)
      local op=$OPTARG
      ;;
    u)
      local jiraUsername=$OPTARG
      ;;
    t)
      local jiraApiToken=$OPTARG
      ;;
    w)
      local workspace=$OPTARG
      ;;
    *)
      printf "invalid option: -${OPTARG}\n" >&2
      exit 1
      ;;
    esac
  done

  case $op in
    ac)
      addCommentToIssue ${jiraUsername} ${jiraApiToken} ${workspace} ${issueKey} "${comment}"
      ;;
    *)
      printf "invalid op: ${op}\n" >&2
      exit 1
      ;;
  esac
}

main "$@"

Этап 2. Пользовательский файл Dockerfile

Создайте собственный файл Dockerfile с инструментами, необходимыми для разработки и развертывания функции AWS Lambda, написанной на Golang. Dockerfile устанавливает несколько утилит, после чего добавляет AWS SAM и Golang. С помощью команды git clone образ скопирует скрипт обновления, созданный на первом этапе, из репозитория Bitbucket. Этот репозиторий нужно заменить на тот, что вы создали для хранения скрипта обновления. Система Docker соберет файл Dockerfile и отправит его в свой репозиторий.

Dockerfile

# syntax = docker/dockerfile:1.3
FROM ubuntu:20.04

MAINTAINER wmarusiak@atlassian.com

WORKDIR /workspace

RUN apt-get update \
&& apt-get -y upgrade \
&& apt-get -y install curl unzip tar openssh-client git jq

RUN curl https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip -L -o aws-sam-cli.zip \
&& mkdir sam-installation \
&& unzip aws-sam-cli.zip -d sam-installation \
&& ./sam-installation/install \
&& sam --version

RUN curl https://go.dev/dl/go1.18.2.linux-amd64.tar.gz -L -o go.tar.gz \
&& rm -rf /usr/local/go \
&& tar -C /usr/local -xzf go.tar.gz

RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan bitbucket.org >> ~/.ssh/known_hosts

RUN --mount=type=ssh git clone git@bitbucket.org:pmmquickstartguides01/updatescript.git

ENV PATH $PATH:/usr/local/go/bin

Этап 3. Файлы YAML конвейера развертывания Concourse-CI

Создайте новый репозиторий под названием concourse и добавьте в него два файла. Файл parent.yml создает конвейер, который отслеживает в репозитории появление новых веток, соответствующих заданному регулярному выражению. Регулярному выражению branch_regex присвоено значение IM-*, поэтому нам подходят все ветки, имя которых начинается с IM-. При создании новых веток, соответствующих регулярному выражению IM-*, файл parent.yml будет создавать новые конвейеры с помощью конфигурации из child.yml. Вам следует изменить parent.yml, указав в нем актуальную версию репозитория SubmitImage. Код SubmitImage см. здесь. Скопируйте код этого репозитория в свой репозиторий с правами на запись.

parent.yml

resource_types:
- name: git-branches
  type: registry-image
  source:
    repository: aoldershaw/git-branches-resource

resources:
- name: feature-branches
  type: git-branches
  source:
    uri: git@bitbucket.org:pmmquickstartguides01/submitimage.git
    branch_regex: IM-*
    private_key: ((bitbucket_ssh_key))

- name: examples
  type: git
  source:
    uri: git@bitbucket.org:pmmquickstartguides01/concourse.git
    private_key: ((bitbucket_ssh_key))

jobs:
- name: set-feature-pipelines
  plan:
  - in_parallel:
    - get: feature-branches
      trigger: true
    - get: examples
  - load_var: branches
    file: feature-branches/branches.json
  - across:
    - var: branch
      values: ((.:branches))
    set_pipeline: dev
    file: examples/child.yml
    vars: {branch: ((.:branch.name))}

Файл child.yml определяет конвейер в четыре этапа. Сначала запускается команда sam validate для проверки того, что файл template.yml сервиса AWS CloudFormation действителен. Затем выполняется команда sam build для сборки пакета SubmitImage в развертываемый артефакт. После этого запускается команда sam deploy для развертывания на AWS обновленного кода SubmitImage. И наконец, конвейер вызывает скрипт обновления, созданный на первом этапе, чтобы оставить комментарий к соответствующей задаче Jira.

child.yml

resources:
- name: repo
  type: git
  source:
    uri: git@bitbucket.org:pmmquickstartguides01/submitimage.git
    branch: ((branch))
    private_key: ((bitbucket_ssh_key))

jobs:
- name: deploy-submit-image
  plan:
  - get: repo
    trigger: true
  - task: run-sam-validate
    config:
      platform: linux
      image_resource:
        type: registry-image
        source:
          repository: docker.atl-paas.net/wmarusiak/ubuntuawssam
          username: ((docker_username))
          password: ((docker_api_key))
      inputs: # add the get step as an input to this task
      - name: repo
      run:
        path: sam
        args: ["validate", "-t", "repo/template.yml"]
      params:
        AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
        AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
        AWS_DEFAULT_REGION: ((AWS_DEFAULT_REGION))
  - task: run-sam-build
    config:
      platform: linux
      image_resource:
        type: registry-image
        source:
          repository: docker.atl-paas.net/wmarusiak/ubuntuawssam
          username: ((docker_username))
          password: ((docker_api_key))
      inputs: # add the get step as an input to this task
      - name: repo
      run:
        path: sam
        args: ["build", "-t", "repo/template.yml"]
      params:
        AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
        AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
        AWS_DEFAULT_REGION: ((AWS_DEFAULT_REGION))
  - task: run-sam-deploy
    config:
      platform: linux
      image_resource:
        type: registry-image
        source:
          repository: docker.atl-paas.net/wmarusiak/ubuntuawssam
          username: ((docker_username))
          password: ((docker_api_key))
      inputs: # add the get step as an input to this task
      - name: repo
      run:
        path: sam
        args: ["deploy", "-t", "repo/template.yml", "--stack-name", "OpenDevOpsSubmitImage", "--s3-bucket", "open-devops-code-us-west-1-756685045356", "--capabilities", "CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]
      params:
        AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
        AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
        AWS_DEFAULT_REGION: ((AWS_DEFAULT_REGION))
  - task: run-update-script
    config:
      platform: linux
      image_resource:
        type: registry-image
        source:
          repository: docker.atl-paas.net/wmarusiak/ubuntuawssam
          username: ((docker_username))
          password: ((docker_api_key))
      input:
      -name: repo
      run:
        path: /workspace/updatescript/concourse-ci-integration.sh
        args: ["-c", "successfully deployed submitImage via concourse-ci", "-k", "((branch))", "-o", "ac", "-u", "((bitbucket_username))", "-t", "((bitbucket_api_key))", "-w", "pmmquickstartguides01"]

Как запустить родительский конвейер

Выполните следующие три команды из каталога, в котором находится файл parent.yml. Первая команда выполняет вход в локальный экземпляр Concourse-CI. Вторая создает конвейер под названием wm на основе конфигурации из parent.yml. Третья возобновляет работу конвейера wm.

fly -t tutorial login -c http://localhost:8080 -u test -p test
fly -t tutorial set-pipeline -p wm -c parent.yml
fly -t tutorial unpause-pipeline -p wm

После выполнения этих команд перейдите к веб-клиенту Concourse-CI, чтобы убедиться, что конвейер wm работает как надо.

Образ веб-клиента Concourse-CI

После запуска команды fly set-pipeline с файлом parent.yml появится конвейер wm. Он отслеживает в репозитории SubmitImage появление новых функциональных веток и создает конвейер для каждой такой ветки, если она соответствует регулярному выражению в файле parent.yml.

Команда fly set-pipeline

Нажмите конвейер wm, чтобы увидеть выполняемые действия. Обратите внимание, что в действии feature-branches указана ветка IM-61. На данный момент это единственная ветка из репозитория SubmitImage, которая соответствует регулярному выражению в parent.yml. Нажмите конвейер dev, который был запущен автоматически, для просмотра выполняемых действий.

Конвейер wm после запуска fly set-pipeline

Обратите внимание на действие для получения репозитория SubmitImage, а также на то, что в качестве ветки указана IM-61. Кроме того, обратите внимание на команды run-sam-validate, run-sam-build, run-sam-deploy и run-update-script.

Тема задачи Jira IM-61

После того как конвейер dev закончит работу, вернитесь к задаче Jira под названием IM-61: минуту назад в ней был опубликован новый комментарий, содержание которого совпадает со строкой комментария из файла child.yml.

Заключение

В этом руководстве мы показали, как настроить конвейер для автоматического развертывания функции AWS Lambda, написанной на Golang, в одном регионе AWS с помощью Concourse-CI. Кроме того, мы рассказали, как использовать bash-скрипт для создания простой интеграции с Jira. Скрипт интеграции можно заметно расширить, подробнее изучив документацию по API REST от Atlassian и применив полученные знания на практике.

Warren Marusiak
Warren Marusiak

Warren is a Canadian developer from Vancouver, BC with over 10 years of experience. He came to Atlassian from AWS in January of 2021.

Поделитесь этой статьей

Рекомендуемые статьи

Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.

Рисунок: DevOps

Сообщество DevOps

Рисунок: DevOps

Образовательные программы DevOps

Рисунок: карта

Начните работу бесплатно

Подпишитесь на информационную рассылку по DevOps

Thank you for signing up