Статьи
Обучающие материалы
Интерактивные руководства
Интеграция 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 придется заменить. В качестве упражнения предлагаем вам самостоятельно добавить нужные секреты с учетом используемых инструментов.
Работа с 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 (Настройки аккаунта).
Нажмите 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 работает как надо.
После запуска команды fly set-pipeline с файлом parent.yml появится конвейер wm. Он отслеживает в репозитории SubmitImage появление новых функциональных веток и создает конвейер для каждой такой ветки, если она соответствует регулярному выражению в файле parent.yml.
Нажмите конвейер wm, чтобы увидеть выполняемые действия. Обратите внимание, что в действии feature-branches указана ветка IM-61. На данный момент это единственная ветка из репозитория SubmitImage, которая соответствует регулярному выражению в parent.yml. Нажмите конвейер dev, который был запущен автоматически, для просмотра выполняемых действий.
Обратите внимание на действие для получения репозитория SubmitImage, а также на то, что в качестве ветки указана IM-61. Кроме того, обратите внимание на команды run-sam-validate, run-sam-build, run-sam-deploy и run-update-script.
После того как конвейер dev закончит работу, вернитесь к задаче Jira под названием IM-61: минуту назад в ней был опубликован новый комментарий, содержание которого совпадает со строкой комментария из файла child.yml.
Заключение
В этом руководстве мы показали, как настроить конвейер для автоматического развертывания функции AWS Lambda, написанной на Golang, в одном регионе AWS с помощью Concourse-CI. Кроме того, мы рассказали, как использовать bash-скрипт для создания простой интеграции с Jira. Скрипт интеграции можно заметно расширить, подробнее изучив документацию по API REST от Atlassian и применив полученные знания на практике.
Поделитесь этой статьей
Следующая тема
Рекомендуемые статьи
Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.