아티클
튜토리얼
대화형 가이드
Concourse-ci와 Atlassian Open DevOps 통합
많은 팀은 요구 사항을 처리하는 데 자체 도구를 활용하거나 오랫동안 사용해 온 레거시 도구를 사용합니다. 팀이 따르는 개발 프로세스에는 이 도구가 꼭 필요합니다. 그러나 해당 도구에는 Jira와의 상용 통합이 없습니다. 다행히 Cloud 개발자 설명서 - Atlassian 개발자에 있는 Atlassian REST API를 사용하면 사용자 지정 통합을 간단하게 만들 수 있습니다. Concourse-CI는 (문서 작성일 기준) Atlassian Marketplace에 통합이 없는 CI/CD 제품입니다. 본 문서에서는 Atlassian REST API를 사용하여 Jira와 Concourse-CI 간의 기본 통합을 만드는 방법을 살펴보겠습니다.
필수 조건
Docker, docker-compose, Concourse-ci를 설정하는 데 필요한 설명서를 참조하세요. Concourse-ci는 Docker에서 실행되며, 간편하게 시작할 수 있도록 docker-compose 스크립트를 제공합니다.
여기에서 Atlassian의 ImageLabeller 데모 애플리케이션에 대해 읽어 보세요. 이 문서에서는 Concourse-CI를 사용하여 ImageLabeller의 SubmitImage 컴포넌트를 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를 설치했으면, 제공된 docker-compose.yml 파일을 사용하여 Concourse-ci를 시작할 수 있습니다.
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와 통합하는 방법에 대한 설명서를 확인할 수 있습니다. 설명서의 지침에 따라 통합을 사용 설정한 후 시작합니다.
Concourse-ci를 시작하는 데 사용되는 docker-compose.yml 파일을 약간 수정해야 통합이 작동합니다. Concourse-ci에서 제공하는 기본 docker-compose.yml 파일을 가져와서
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-compose up -d를 실행하기 전후에 docker ps -a를 실행하여 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 파이프라인
Concourse-ci 설명서 https://concourse-ci.org/tutorial-hello-world.html에 따라 hello world 파이프라인을 설정합니다. Fly cli를 소개하고 명령줄에서 Concourse-ci 작업에 익숙해지기 위해 필요한 단계입니다.
다음 섹션에서는 Concourse-ci를 사용하여 Golang으로 작성된 AWS Lambda를 단일 AWS 리전에 배포하는 방법과 프로세스의 단계인 Jira 이슈의 업데이트를 작성하는 방법을 살펴봅니다.
Concourse-ci로 SubmitImage 배포
SubmitImage Lambda를 Concourse-ci로 배포하는 방법은 세 단계로 구성됩니다. 첫 번째 단계는 Jira Cloud REST API를 사용하여 Jira 이슈에 댓글을 작성하는 간단한 Bash 스크립트를 작성하는 것입니다. 만들 수 있는 가장 간단한 통합입니다. 두 번째 단계는 Golang AWS Lambda를 빌드하고 배포하는 데 필요한 도구를 사용하여 Docker 이미지를 만드는 것입니다. 마지막 단계는 한 쌍의 Concourse-ci 구성 파일을 작성하는 것입니다. 첫 번째 구성 파일인 parent.yml은 SubmitImage 리포지토리에 새 브랜치가 있는지 모니터링하고 새 파이프라인을 스풀링하여 해당 브랜치의 커밋을 배포합니다. 두 번째 구성 파일인 child.yml은 변경 사항을 배포하는 데 필요한 단계를 정의합니다.
1단계 - REST API를 통해 Jira 이슈 업데이트
이 업데이트 스크립트는 Jira Cloud 플랫폼 REST API를 사용하여 특정 Jira 이슈에 댓글을 작성합니다. 스크립트를 실행할 때마다 설정해야 하는 필수 매개 변수가 다섯 개 있습니다. jiraUsername, jiraApiToken, workspace는 보통 특정 파이프라인을 각각 실행하는 것과 같습니다. issueKey는 배포 중인 특정 브랜치의 브랜치 이름에 따라 달라집니다. 브랜치 이름에 Jira 이슈 ID를 입력하고 특정 이슈 작업을 할 때는 메시지를 커밋하는 것이 Jira의 모범 사례입니다. 본 문서에서는 사용자가 모범 사례를 따르며, 브랜치 이름이 Jira 이슈 ID와 같다고 가정합니다.
매개 변수를 찾는 방법
Jira 사용자 이름
Jira 사용자 이름은 Jira에 로그인할 때 사용하는 이메일 주소입니다.
Jira API 토큰
계정 설정으로 이동합니다
보안을 클릭합니다
API 토큰 만들기 및 관리
작업 영역을 클릭합니다
https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203과 같은 Jira 인스턴스 URL의 경우 작업 영역은 pmmquickstartguide01입니다.
이슈 키
https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203과 같은 Jira 이슈 URL의 경우 Jira 이슈 키는 IM-203입니다. 통합에서 올바른 위치에 업데이트를 작성할 수 있도록 커밋 메시지와 브랜치 이름에 Jira 이슈 ID를 입력하세요.
댓글
댓글에는 무엇이든 입력할 수 있습니다.
업데이트 스크립트
업데이트 스크립트는 Jira 이슈 댓글 REST API 엔드포인트를 사용하는 간단한 Bash 셸 스크립트입니다. 이 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
Golang으로 작성한 AWS Lambda를 빌드하고 배포하는 데 필요한 도구를 이용해 사용자 지정 Dockerfile을 만듭니다. Dockerfile은 유틸리티를 몇 개 설치한 다음 AWS SAM 및 Golang을 추가합니다. 이미지 Git은 1단계에서 Bitbucket 리포지토리에서 만든 업데이트 스크립트를 복제합니다. 이 Bitbucket 리포지토리는 업데이트 스크립트를 보관하기 위해 만든 리포지토리로 교체해야 합니다. Docker가 이 Dockerfile을 빌드하고 Docker 리포지토리로 푸시합니다.
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단계 - Concourse-ci 배포 파이프라인 yaml 파일
concourse라는 새 리포지토리를 만들고 파일 두 개를 저장합니다. parent.yml은 리포지토리 정규식에 맞는 새 브랜치가 있는지 모니터링하는 파이프라인을 만듭니다. branch_regex는 IM-로 시작하는 모든 브랜치와 일치하는 IM-*입니다. parent.yml은 정규식 IM-*와 일치하는 새 브랜치가 만들어지면 child.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를 실행하여 AWS CloudFormation template.yml 파일이 유효한지 확인합니다. 그런 다음, sam build를 실행하여 SubmitImage 패키지를 배포 가능한 아티팩트로 빌드합니다. 세 번째로 sam deploy를 실행하여 업데이트된 SubmitImage 코드를 AWS에 배포합니다. 마지막으로 파이프라인은 1단계에서 작성한 업데이트 스크립트를 호출하여 일치하는 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 인스턴스에 로그인합니다. 두 번째 명령은 parent.yml의 구성을 기반으로 wm이라는 파이프라인을 만듭니다. 세 번째 명령은 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 파이프라인이 시작되고 실행 중인지 확인합니다.
parent.yml의 fly set-pipeline을 실행하면 wm 파이프라인이 있습니다. 이 파이프라인은 SubmitImage에 새로운 기능 브랜치가 있는지 모니터링하고, parent.yml의 정규식과 일치하는 각 기능 브랜치에 대한 파이프라인을 만듭니다.
실행되는 단계를 보려면 wm 파이프라인을 클릭합니다. 기능 브랜치 단계에 IM-61 브랜치가 나열되는 것에 주목하세요. parent.yml의 정규식과 일치하면서 현재 SubmitImage에 있는 유일한 브랜치입니다. 자동으로 시작된 dev 파이프라인을 클릭하면 파이프라인이 실행하는 단계를 볼 수 있습니다.
SubmitImage 리포지토리를 가져오는 단계가 있으며 브랜치가 IM-61이라는 것에 주목하세요. 또한 un-sam-validate, run-sam-build, run-sam-deploy, and run-update-script 단계가 있다는 것도 확인할 수 있습니다.
dev 파이프라인 실행이 끝난 후, IM-61 Jira 이슈로 돌아가면 1분 전에 기록된 child.yml의 댓글 문자열과 일치하는 새 댓글을 확인할 수 있습니다
결론...
본 가이드에서는 Concourse-ci를 사용하여 Golang AWS Lambda를 단일 AWS 리전에 자동으로 배포하는 파이프라인을 설정하는 방법을 살펴봅니다. 또한 Bash 셸 스크립트를 사용하여 Jira와의 간단한 통합을 작성하는 방법도 알아봅니다. 여기에 나와 있는 Atlassian REST API 설명서를 자세히 살펴보면 통합 스크립트를 폭넓게 확장할 수 있습니다.
이 문서 공유
다음 토픽
여러분께 도움을 드릴 자료를 추천합니다.
이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.