Close

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.

segredos do Bitbucket e do Docker

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

Configurações da conta para tokens de API do JIRA

Clique em Segurança

segurança da conta

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.

imagem do cliente web do Concourse-CI

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.

comando fly set pipeline

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.

pipeline WM após o comando fly set pipeline

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.

Resumo do item GI-61 do Jira

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.

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.

Compartilhar este artigo

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.

Ilustração do DevOps

Comunidade de DevOps

Ilustração do DevOps

Caminho de aprendizagem de DevOps

Ilustração do mapa

Comece gratuitamente

Inscreva-se para receber a newsletter de DevOps

Thank you for signing up