Close

Integrazione di Concourse CI e Atlassian Open DevOps

Molti team utilizzano i propri strumenti per gestire le proprie esigenze o dispongono di strumenti legacy che usano da anni. Questi strumenti sono essenziali per il processo di sviluppo seguito da un team, ma non dispongono di integrazioni pronte all'uso con Jira. Fortunatamente, creare un'integrazione personalizzata utilizzando le API REST di Atlassian disponibili nella documentazione per sviluppatori Cloud - Atlassian Developer è semplicissimo. Concourse CI è un prodotto CI/CD che, al momento della stesura di questo articolo, non è integrato nell'Atlassian Marketplace. Questo articolo spiega come creare un'integrazione di base tra Jira e Concourse CI utilizzando le API REST di Atlassian.

Prerequisiti

Usa la documentazione necessaria per configurare Docker, docker-compose e Concourse CI. Concourse CI funziona su Docker e fornisce uno script docker-compose per semplificare le operazioni iniziali.

Scopri di più sull'applicazione demo ImageLabeller di Atlassian qui. Questo articolo spiega come utilizzare Concourse CI per distribuire il componente SubmitImage di ImageLabeller su AWS.

Docker

Configura Docker e docker-compose seguendo la documentazione associata:

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

Concourse CI

Una volta installati Docker e docker-compose, puoi avviare Concourse CI utilizzando il file docker-compose.yml fornito.

Segui la guida introduttiva di Concourse CI per iniziare a usare https://concourse-ci.org/quick-start.html#docker-compose-concourse. Questa guida richiede il passaggio sicuro delle credenziali a Concourse CI. La guida utilizza l'integrazione di Concourse CI con AWS Secrets Manager per questo scopo.

Integrazione di Concourse CI con AWS Secrets Manager

Qui puoi trovare la documentazione su come integrare Concourse CI con AWS Secrets Manager. Segui le istruzioni nella documentazione per abilitare l'integrazione e iniziare.

Il file docker-compose.yml utilizzato per avviare Concourse CI deve essere leggermente modificato affinché l'integrazione funzioni. Prendi il file docker-compose.yml predefinito fornito da Concourse CI e aggiungi
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>

Una volta che l'integrazione è stata configurata e Concourse CI è in esecuzione con l'integrazione abilitata, aggiungi i seguenti segreti ad 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

Potrebbe essere necessario sostituire i segreti di Bitbucket e Docker se il lettore non utilizza Bitbucket per il codice e JFrog come repository Docker. Apportare modifiche per adattarlo agli strumenti individuali del lettore viene lasciato come esercizio.

segreti di bitbucket e docker

Lavorare con Concourse CI

Esegui docker ps -a prima e dopo aver eseguito docker-compose up -d per vedere se Concourse CI è stato avviato correttamente.

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

Vai su http://localhost:8080/ dopo aver eseguito 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

Al momento non sono state definite pipeline.

Una pipeline Hello World

Configura una pipeline Hello World seguendo questa documentazione di Concourse CI: https://concourse-ci.org/tutorial-hello-world.html. Questo è necessario per introdurre la CLI Fly e abituarsi a lavorare con Concourse CI dalla riga di comando.

La prossima sezione spiega come distribuire un AWS Lambda scritto in Golang in una singola regione AWS con Concourse CI e come scrivere un aggiornamento a un ticket Jira come parte del processo.

Distribuisci SubmitImage con Concourse CI

Ci sono tre passaggi per distribuire SubmitImage Lambda con Concourse CI. Il primo passaggio consiste nello scrivere un semplice script bash che utilizzi l'API REST di Jira Cloud per scrivere un commento in un ticket Jira. Questa è l'integrazione più semplice che possiamo creare. Il secondo passaggio consiste nel creare un'immagine Docker con gli strumenti necessari per creare e distribuire un AWS Lambda Golang. Il passaggio finale consiste nello scrivere due file di configurazione di Concourse CI. Il primo file di configurazione, parent.yml, monitora il repository SubmitImage alla ricerca di nuovi branch e avvia nuove pipeline per distribuire i commit da tali branch. Il secondo file di configurazione, child.yml, definisce l'insieme di passaggi necessari per distribuire una modifica.

Passaggio 1: aggiorna i ticket Jira tramite l'API REST

Questo script di aggiornamento utilizza l'API REST della piattaforma Jira Cloud per scrivere un commento a un ticket Jira specifico. Ci sono cinque parametri obbligatori che devono essere impostati ogni volta che viene eseguito lo script. I parametri jiraUsername, jiraApiToken e workspace in genere sono gli stessi per ogni esecuzione di una particolare pipeline. Il parametro issueKey dipenderà dal nome dello specifico branch che si sta distribuendo. È una best practice Jira inserire l'ID del ticket Jira nei nomi dei branch e i messaggi di commit quando si lavora su un particolare ticket. Questo articolo presuppone che venga seguita la best practice e che i nomi dei branch corrispondano all'ID del ticket Jira.

Come trovare i parametri
Nome utente Jira


Il nome utente Jira è l'indirizzo e-mail utilizzato per accedere a Jira.

Token API di Jira
Vai alle impostazioni dell'account

Impostazioni dell'account per i token API di Jira

Clicca su Sicurezza

sicurezza dell'account

Clicca su Crea e gestisci i token API

Spazio di lavoro

Dato l'URL di un'istanza Jira come https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203, lo spazio di lavoro è pmmquickstartguide01.

Identificatore del ticket

Dato l'URL di un ticket Jira come https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203, l'identificatore ticket di Jira è IM-203. Inserisci l'ID del ticket Jira nei messaggi di commit e nei nomi dei branch in modo che l'integrazione possa scrivere gli aggiornamenti nella posizione corretta.

Commenta

Il commento può essere qualsiasi cosa.

Lo script di aggiornamento

Lo script di aggiornamento è un semplice script bash shell che utilizza l'endpoint dell'API REST per i commenti ai ticket Jira. Qui puoi trovare la documentazione per questa chiamata API. Lo script può essere modificato per fornire un'integrazione più profonda seguendo lo schema fornito per effettuare chiamate API aggiuntive. Copia questo script in un file chiamato concourse-ci-integration.sh e inseriscilo in un repository Bitbucket o GitHub chiamato 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 "$@"

Passaggio 2: Dockerfile personalizzato

Crea un Dockerfile personalizzato con gli strumenti necessari per creare e distribuire un AWS Lambda scritto in Golang. Il Dockerfile installa alcune utilità, quindi aggiunge AWS SAM e Golang. L'immagine Git clona lo script di aggiornamento creato nel passaggio 1 da un repository Bitbucket. Devi sostituire questo repository Bitbucket con qualsiasi repository che hai creato per contenere lo script di aggiornamento. Docker crea questo Dockerfile e lo invia a un repository Docker.

Docker

# 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

Passaggio 3: file YAML della pipeline di distribuzione di Concourse CI

Crea un nuovo repository chiamato concourse e inseriscici due file. Parent.yml crea una pipeline che monitora un repository per i nuovi branch che corrispondono a un'espressione regolare. Il branch_regex è IM-*, che corrisponde a tutti i branch che iniziano con IM-. Parent.yml creerà una nuova pipeline utilizzando la configurazione in child.yml quando viene creato un nuovo branch che corrisponde all'espressione regolare IM-*. Dovresti aggiornare questo file in modo che rimandi alla tua versione del repository SubmitImage. Il codice SubmitImage può essere trovato qui. Copia il codice di questo repository in un repository con autorizzazioni di scrittura.

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 definisce una pipeline con quattro passaggi. Innanzitutto, esegue sam validate per verificare che il file template.yml di AWS CloudFormation sia valido. Successivamente, esegue sam build per creare il pacchetto SubmitImage in un artefatto distribuibile. In terzo luogo, esegue sam deploy per distribuire il codice SubmitImage aggiornato su AWS. Infine, la pipeline richiama lo script di aggiornamento scritto nel passaggio 1 per scrivere un commento al ticket Jira corrispondente.

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"]

Come avviare la pipeline principale

Esegui i seguenti tre comandi dalla directory con parent.yml. Il primo comando consente di accedere all'istanza Concourse CI in esecuzione localmente. Il secondo comando crea una pipeline chiamata wm in base alla configurazione in parent.yml. Il terzo comando riattiva la 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

Vai al client web di Concourse CI dopo aver eseguito questi tre comandi per vedere se la pipeline wm è attiva e funzionante.

immagine del client web di concourse ci

Dopo aver eseguito fly set-pipeline con parent.yml c'è una pipeline wm. Questa pipeline monitora SubmitImage per eventuali nuovi branch di funzioni e crea una pipeline per ogni branch di funzioni corrispondente all'espressione regolare in parent.yml.

pipeline fly set

Clicca sulla pipeline wm per vedere i passaggi eseguiti. Nota che il passaggio feature-branches presenta un branch IM-61. Questo è l'unico branch attualmente esistente in SubmitImage che corrisponde all'espressione regolare in parent.yml. Clicca sulla pipeline di sviluppo che è stata avviata automaticamente per vedere i passaggi che esegue.

Pipeline WM dopo la pipeline fly set

Nota che c'è un passaggio per ottenere il repository SubmitImage e che il branch è IM-61. Nota anche che ci sono i passaggi run-sam-validate, run-sam-build, run-sam-deploy e run-update-script.

Riepilogo del ticket Jira IM 61

Al termine dell'esecuzione della pipeline di sviluppo, torna al ticket Jira IM-61 e nota che c'è un nuovo commento registrato un minuto fa che corrisponde alla stringa di commento di child.yml.

In conclusione...

Questa guida spiega come configurare una pipeline per distribuire automaticamente un AWS Lambda Golang in una singola regione AWS utilizzando Concourse CI. Questa guida spiega anche come usare uno script bash shell per scrivere una semplice integrazione con Jira. Lo script di integrazione può essere notevolmente ampliato approfondendo la documentazione dell'API REST di Atlassian disponibile qui.

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.

Condividi l'articolo

Letture consigliate

Aggiungi ai preferiti queste risorse per ricevere informazioni sui tipi di team DevOps e aggiornamenti continui su DevOps in Atlassian.

Illustrazione su Devops

Community DevOps

Illustrazione su Devops

Percorso di apprendimento DevOps

Illustrazione di una mappa

Inizia gratis

Iscriviti alla nostra newsletter DevOps

Thank you for signing up