Integração entre o Concourse-CI e o Atlassian Open DevOps
Muitas equipes criam ferramentas próprias para atender as necessidades ou têm ferramentas antigas que usam há anos. São ferramentas essenciais para o processo de desenvolvimento adotado pelas equipes, mas não têm integrações prontas para uso com o Jira. No entanto, é fácil criar a integração personalizada usando as APIs REST da Atlassian contidas na Documentação do Cloud para desenvolvedores - Atlassian Developer . O Concourse-CI é um produto de integração/implementação contínuas (IC) que, no momento da redação deste artigo, não tem integração do Atlassian Marketplace. Este artigo demonstra como gerar uma integração básica entre o Jira e o Concourse-CI usando as APIs REST da Atlassian.
Pré-requisitos
Use a documentação necessária para configurar o Docker, o Docker Compose e o Concourse-CI. O Concourse-CI é executado no Docker e dispo script do Docker Compose para simplificar o início.
Saiba mais sobre o ImageLabeller, o aplicativo de demonstração da Atlassian, aqui. Este artigo demonstra como usar o Concourse-cI para implementar o componente SubmitImage do ImageLabeller no AWS.
Docker
Configure o Docker e o Docker Compose seguindo as respectivas documentações:
Docker: https://docs.docker.com/get-docker/
Docker Compose: https://docs.docker.com/compose/install/
Concourse-CI
Assim que o Docker e o Docker Compose estiverem instalados, o Concourse-CI pode ser iniciado usando o arquivo docker-compose.yml disponibilizado.
Siga o guia de início rápido para começar a usar o Concourse-CI https://concourse-ci.org/quick-start.html#docker-compose-concourse. Este guia exige a transferência segura de credenciais para o Concourse-CI. O guia utiliza a integração entre o Concourse-CI e o AWS Secrets Manager para essa finalidade.
Integração entre o Concourse-CI e o AWS Secrets Manager
Aqui está a documentação sobre como realizar a integração entre o Concourse-CI e o AWS Secrets Manager. Siga as instruções na documentação para ativar e começar a usar a integração.
Para que a integração funcione, é necessário realizar algumas modificações no arquivo docker-compose.yml, usado para iniciar o Concourse-CI. No arquivo padrão docker-compose.yml fornecido pelo Concourse-CI e adicione
CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY, CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY e 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>
Depois que a integração estiver configurada e o Concourse-CI estiver funcionando com a integração ativada, adicione os segredos a seguir ao 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
Pode ser necessário substituir os segredos do Bitbucket e do Docker se você não estiver usando o Bitbucket para a codificação e o JFrog como repositório do Docker. Como um exercício, faça os ajustes necessários para adequar as ferramentas que você utiliza.
Como trabalhar com o Concourse-CI
Execute o comando docker ps -a antes e depois do comando docker-compose up -d para ver se o Concourse-ci foi iniciado sem erros.
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
Acesse http://localhost:8080/ depois de executar o comando fly -t tutorial login -c http://localhost:8080 -u test -p test
fly -t tutorial login -c http://localhost:8080 -u test -p test
logging in to team 'main'
target saved
Não há pipelines definidos no momento.
Pipeline hello world
Configure o pipeline hello world seguindo a documentação do Concourse-CI a seguir: https://concourse-ci.org/tutorial-hello-world.html. Isso é necessário para introduzir a interface de linha de comando (CLI) Fly e se acostumar a trabalhar com o Concourse-CI a partir da linha de comando.
A próxima seção demonstra como implementar o AWS Lambda criado em Golang em uma única região do AWS com o Concourse-CI e como criar a atualização para o item do Jira como parte do processo.
Implementar o SubmitImage com o Concourse-CI
Há três etapas para implementar o SubmitImage no Lambda com o Concourse-CI. A primeira etapa é criar um script bash simples que use a API REST do Jira Cloud para escrever um comentário em item do Jira. Essa é a integração mais simples que pode ser criada. A segunda etapa é criar a imagem do Docker com as ferramentas necessárias para gerar e implementar o AWS Lambda criado em Golang. A etapa final é criar um par de arquivos de configuração do Concourse-CI. O primeiro arquivo de configuração, o parent.yml, monitora o repositório SubmiImage em busca de novas ramificações e cria novos pipelines para implementar confirmações dessas ramificações. O segundo arquivo de configuração, o child.yml, define o conjunto necessário de etapas para implementar a alteração.
Etapa 1 - Atualizar itens do Jira por meio da API REST
Esse script de atualização usa a API REST da plataforma Jira Cloud para escrever um comentário em um item específico do Jira. Há cinco parâmetros necessários que devem ser definidos toda vez que o script é executado. O jiraUserName (nome de usuário do Jira), o jiraApiToken (token de API do Jira) e a área de trabalho costumam ser os mesmos para cada execução do pipeline específico. A IssueKey (chave do item) vai depender do nome da ramificação específica que está sendo implementada. Uma prática recomendada do Jira é colocar o ID do item do Jira nos nomes das ramificações e enviar mensagens de confirmação ao trabalhar em um item específico. Este artigo pressupõe que as práticas recomendadas estão sendo seguidas e que os nomes das ramificações são equivalentes ao ID do item do Jira.
Como localizar os parâmetros
Nome de usuário do Jira
O nome de usuário do Jira é o endereço de e-mail usado para fazer login no Jira.
Token de API do Jira
Acesse as Configurações da conta
Clique em Segurança
Clique em Criar e gerenciar tokens de API
Área de trabalho
Para a URL de instância do Jira, como https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 a área de trabalho é pmmquickstartguide01.
Chave do item
Para a URL de item do Jira, como https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 a chave do item do Jira é GI-203. Insira o ID do item do Jira nas mensagens de confirmação e nos nomes das ramificações para que a integração possa gravar as atualizações no local correto.
Comentário
O comentário pode ser qualquer coisa.
O script de atualização
O script de atualização é um script de shell bash simples que usa o terminal da API REST de comentário de itens do Jira. Aqui está a documentação para essa chamada de API. O script pode ser modificado para disponibilizar a integração mais profunda seguindo o padrão disponibilizado para fazer chamadas adicionais à API. Copie esse script para um arquivo chamado concourse-ci-integration.sh e o coloque em um repositório do Bitbucket ou do GitHub chamado updateScript.
#!/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 "$@"
Etapa 2 - Dockerfile personalizado
Crie um Dockerfile personalizado com as ferramentas necessárias para gerar e implementar o AWS Lambda criado em Golang. O Dockerfile instala alguns utilitários e adiciona o AWS SAM e o Golang. A imagem do Git clona o script de atualização criado na Etapa 1 a partir de um repositório do Bitbucket. É necessário substituir esse repositório do Bitbucket por qualquer repositório criado para armazenar o script de atualização. O Docker cria esse Dockerfile e o envia para um repositório 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
Etapa 3 - Arquivos yaml do pipeline de implementação do Concourse-CI
Crie um novo repositório chamado Concourse e adicione dois arquivos nele. O arquivo parent.yml cria um pipeline que monitora um repositório em busca de novas ramificações que correspondam a expressão regular. A expressão regular da ramificação (branch_regex) é IM-* que corresponde a todas as ramificações que começam com IM-. O parent.yml vai criar um novo pipeline usando a configuração no arquivo child.yml quando a nova ramificação que corresponda à expressão regular IM-* for criada. Esse arquivo deve ser atualizado para especificar a sua própria versão do repositório SubmitImage. O código do SubmitImage pode ser encontrado aqui. Copie o código desse repositório para um repositório com permissões de gravação.
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))}
O arquivo child.yml define o pipeline com quatro etapas. Primeiro, ele executa o comando sam validate para verificar se o arquivo template.yml do AWS CloudFormation é válido. Em seguida, o comando sam build é executado para criar o pacote SubmitImage em um artefato implementável. Em terceiro lugar, o comando sam deploy é executado para implementar o código atualizado do SubmiImage no AWS. Por fim, o pipeline chama o script de atualização criado na etapa 1 para escrever um comentário no item correspondente do 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"]
Como iniciar o pipeline pai
Execute os três comandos a seguir no diretório com o arquivo parent.yml. O primeiro comando efetua login na instância do Concourse-CI em execução local. O segundo comando cria um pipeline chamado wm com base na configuração existente no arquivo parent.yml. O terceiro comando aciona o pipeline 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
Acesse o cliente web do Concourse-CI depois de executar esses três comandos para ver se o pipeline wm está funcionando.
Depois de executar o comando fly set-pipeline com o arquivo parent.yml, tem o pipeline wm. Esse pipeline monitora o SubmitImage em busca de novas ramificações de função e cria um pipeline para cada ramificação de função que corresponda à expressão regular existente em parent.yml.
Clique no pipeline wm para ver as etapas executadas. Observe que a etapa feature-branches (ramificações de função) lista a ramificação chamada GI-61. Essa é a única ramificação no momento em SubmitImage que corresponde à expressão regular existente em parent.yml. Clique no pipeline dev com início automático para ver as etapas executadas.
Observe que há uma etapa para obter o repositório SubmitImage e que a ramificação é GI-61. Observe também que há etapas run-sam-validate, run-sam-build, run-sam-deploy e run-update-script.
Depois que o pipeline dev terminar de realizar todos os procedimentos, volte ao item GI-61 do Jira e observe que há um novo comentário registrado há um minuto que corresponde à sequência de comentários do arquivo child.yml
Conclusão…
Este guia demonstra como configurar o pipeline para implementação automática do AWS Lambda criado em Golang em uma única região do AWS usando o Concourse-CI. Ele também demonstra como usar um script de shell bash para criar a integração simples com o Jira. O script de integração pode ser expandido com o aprofundamento na documentação da API REST da Atlassian disponível aqui.
Compartilhar este artigo
Próximo tópico
Leitura recomendada
Marque esses recursos para aprender sobre os tipos de equipes de DevOps ou para obter atualizações contínuas sobre DevOps na Atlassian.