Close

Intégration de Concourse CI et d'Atlassian Open DevOps

De nombreuses équipes utilisent leurs propres outils pour répondre à leurs besoins ou des outils hérités depuis des années. Ces outils sont essentiels au processus de développement qu'elles suivent, mais ils ne disposent pas d'intégrations standard à Jira. Heureusement, il est facile de créer une intégration personnalisée à l'aide des API REST Atlassian reprises dans la documentation dédiée aux développeurs Cloud - Atlassian Developer. Concourse CI est un produit de CI/CD qui, au moment de la rédaction de cet article, n'est pas intégré à l'Atlassian Marketplace. Cet article explique comment créer une intégration de base entre Jira et Concourse CI à l'aide des API REST Atlassian.

Prérequis

Utilisez la documentation nécessaire pour configurer Docker, Docker Compose et Concourse CI. Concourse CI s'exécute sur Docker et fournit un script Docker Compose pour vous aider à vous lancer facilement.

Pour en savoir plus sur l'application de démo ImageLabeller d'Atlassian, cliquez ici. Cet article explique comment utiliser Concourse CI pour déployer le composant SubmitImage d'ImageLabeller sur AWS.

Docker

Configurez Docker et Docker Compose en suivant la documentation associée :

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

Concourse CI

Une fois Docker et Docker Compose installés, vous pouvez démarrer Concourse CI en utilisant le fichier docker-compose.yml fourni.

Suivez le guide de démarrage rapide de Concourse CI pour vous lancer, à l'adresse https://concourse-ci.org/quick-start.html#docker-compose-concourse. Ce guide nécessite de transmettre des informations d'identification à Concourse CI en toute sécurité. Il utilise l'intégration Concourse CI AWS Secrets Manager à cette fin.

Intégration de Concourse CI à AWS Secrets Manager

Voici la documentation expliquant comment intégrer Concourse CI à AWS Secrets Manager. Suivez les instructions de la documentation pour activer l'intégration et vous lancer.

Le fichier docker-compose.yml utilisé pour démarrer Concourse CI doit être légèrement modifié pour que l'intégration fonctionne. Prenez le fichier docker-compose.yml par défaut fourni par Concourse CI et ajoutez
CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY, CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY et 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>

Une fois que l'intégration sera configurée et que Concourse CI fonctionnera avec l'intégration activée, ajoutez les secrets suivants à 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

Les secrets Bitbucket et Docker devront peut-être être remplacés si le lecteur n'utilise pas Bitbucket pour son code, ni JFrog comme dépôt Docker. Vous pouvez les ajuster aux outils individuels du lecteur en guise d'exercice.

secrets Bitbucket et Docker

Utiliser Concourse CI

Lancez docker ps -a avant et après avoir lancé docker-compose up -d pour vérifier que Concourse CI a démarré correctement.

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

Accédez à http://localhost:8080/ après avoir exécuté « 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

Aucun pipeline n'est défini pour le moment.

Un pipeline Hello World

Configurez un pipeline Hello World en suivant cette documentation Concourse CI : https://concourse-ci.org/tutorial-hello-world.html. Cette action est nécessaire pour présenter l'interface de ligne de commande Fly et se familiariser avec l'utilisation de Concourse CI depuis la ligne de commande.

La section suivante explique comment déployer un service AWS Lambda écrit en Golang dans une seule région AWS avec Concourse CI et comment rédiger une mise à jour pour un ticket Jira dans le cadre du processus.

Déployer SubmitImage avec Concourse CI

Vous devez suivre trois étapes pour déployer SubmitImage Lambda avec Concourse CI. La première consiste à écrire un script bash simple qui utilise l'API REST Jira Cloud pour écrire un commentaire dans un ticket Jira. Il s'agit de l'intégration la plus simple. La deuxième étape consiste à créer une image Docker avec les outils nécessaires pour développer et déployer un service AWS Lambda en Golang. La dernière étape consiste à écrire deux fichiers de configuration Concourse CI. Le premier, parent.yml, surveille le dépôt SubmitImage à la recherche de nouvelles branches et crée des pipelines pour déployer des commits depuis ces branches. Le deuxième fichier de configuration, child.yml, définit les étapes nécessaires pour déployer un changement.

Étape 1 : Mettre à jour les tickets Jira via l'API REST

Ce script de mise à jour utilise l'API REST de la plateforme Jira Cloud pour écrire un commentaire dans un ticket Jira spécifique. Cinq paramètres doivent être définis à chaque exécution du script. Le nom d'utilisateur Jira, le jeton d'API Jira et l'espace de travail sont généralement les mêmes pour chaque exécution d'un pipeline spécifique. La clé de ticket dépendra du nom de la branche en cours de déploiement. Selon les bonnes pratiques Jira, il convient d'intégrer l'ID du ticket Jira aux noms de branche et de commiter les messages lorsque vous travaillez sur un ticket précis. Cet article part du principe que les bonnes pratiques sont suivies et que les noms de branche sont similaires à l'ID du ticket Jira.

Comment trouver les paramètres
Nom d'utilisateur Jira


Le nom d'utilisateur Jira est l'adresse e-mail utilisée pour se connecter à Jira.

Jeton d'API Jira
Accédez aux paramètres du compte.

jetons d'API Jira dans les paramètres du compte

Cliquez sur Sécurité.

sécurité du compte

Cliquez sur Créer et gérer des jetons d'API

Espace de travail

Avec l'URL d'une instance Jira comme https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203, l'espace de travail est pmmquickstartguide01.

Clé de ticket

Avec l'URL d'un ticket Jira, comme https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203, la clé du ticket Jira est IM-203. Insérez l'ID du ticket Jira dans les messages de commit et les noms de branche afin que l'intégration puisse écrire les mises à jour au bon endroit.

Commentaire

Le commentaire peut être n'importe quoi.

Script de mise à jour

Le script de mise à jour est un script shell Bash simple qui utilise le point de terminaison de l'API REST pour le commentaire du ticket Jira. Voici la documentation de cet appel d'API. Le script peut être modifié pour permettre une intégration plus étroite en suivant le modèle fourni pour effectuer des appels d'API supplémentaires. Copiez ce script dans un fichier appelé concourse-ci-integration.sh et placez-le dans un dépôt Bitbucket ou GitHub nommé 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 "$@"

Étape 2 : Personnaliser un document Dockerfile

Créez un document Dockerfile personnalisé avec les outils nécessaires pour développer et déployer un service AWS Lambda écrit en Golang. Le document Dockerfile installe quelques utilitaires, puis ajoute AWS SAM et Golang. L'image Git clone le script de mise à jour créé à l'étape 1 à partir d'un dépôt Bitbucket. Vous devez remplacer ce dépôt Bitbucket par le dépôt que vous avez créé pour le script de mise à jour. Docker crée ce document Dockerfile et le pushe vers un dépôt 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

Étape 3 : Fichiers yaml du pipeline de déploiement de Concourse CI

Créez un dépôt appelé concourse et placez-y deux fichiers. Parent.yml crée un pipeline qui surveille un dépôt à la recherche de nouvelles branches correspondant à une expression régulière. L'expression régulière branch_regex est IM-* qui correspond à toutes les branches commençant par IM-. Parent.yml créera un pipeline en utilisant la configuration de child.yml lorsqu'une branche correspondant à l'expression régulière IM-* sera créée. Vous devriez mettre à jour ce fichier pour renvoyer vers votre propre version du dépôt SubmitImage. Le code SubmitImage est disponible ici. Copiez le code de ce dépôt dans un dépôt disposant des autorisations d'écriture.

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))}

Le fichier child.yml définit un pipeline en quatre étapes. Tout d'abord, il exécute « sam-validate » pour vérifier la validité du fichier template.yml AWS CloudFormation. Ensuite, il exécute « sam-build » pour transformer le package SubmitImage en un artefact déployable. Puis il exécute « sam-deploy » pour déployer le code SubmitImage mis à jour sur AWS. Enfin, le pipeline invoque le script de mise à jour créé à l'étape 1 pour écrire un commentaire dans le ticket Jira correspondant.

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

Comment démarrer le pipeline parent

Exécutez les trois commandes suivantes depuis le répertoire contenant le fichier parent.yml. La première commande se connecte à l'instance Concourse CI exécutée localement. La deuxième crée un pipeline appelé « wm » basé sur la configuration du fichier parent.yml. La troisième commande met fin à la pause du 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

Accédez au client web Concourse CI après avoir exécuté ces trois commandes pour vérifier que le pipeline wm est opérationnel.

image du client web Concourse CI

Après avoir exécuté fly set-pipeline avec le fichier parent.yml, le pipeline wm est disponible. Ce pipeline surveille SubmitImage à la recherche de nouvelles branches de fonctionnalité et crée un pipeline pour chaque branche de fonctionnalité correspondant à l'expression régulière du fichier parent.yml.

fly set-pipeline

Cliquez sur le pipeline wm pour voir les étapes exécutées. Notez que l'étape feature-branches répertorie une branche IM-61. C'est la seule branche existante dans SubmitImage qui correspond à l'expression régulière du fichier parent.yml. Cliquez sur le pipeline de développement qui a été démarré automatiquement pour voir les étapes exécutées.

pipeline wm après fly set-pipeline

Notez qu'il y a une étape pour obtenir le dépôt SubmitImage et que la branche est IM-61. Notez également qu'il existe des étapes run-sam-validate, run-sam-build, run-sam-deploy et run-update-script.

résumé du ticket Jira IM 61

Une fois l'exécution du pipeline de développement terminée, revenez au ticket Jira IM-61 et notez qu'un nouveau commentaire enregistré une minute auparavant correspond à la chaîne de commentaires du fichier child.yml.

Conclusion…

Ce guide explique comment configurer un pipeline pour déployer automatiquement un service AWS Lambda en Golang vers une seule région AWS à l'aide de Concourse CI. Il montre également comment utiliser un script shell Bash pour créer une intégration simple à Jira. Le script d'intégration peut être considérablement développé en étudiant plus en détail la documentation de l'API REST Atlassian disponible ici.

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.

Partager cet article

Lectures recommandées

Ajoutez ces ressources à vos favoris pour en savoir plus sur les types d'équipes DevOps, ou pour les mises à jour continues de DevOps chez Atlassian.

Illustration DevOps

Communauté DevOps

Illustration DevOps

Parcours de formation DevOps

Illustration d'une carte

Essayez la solution gratuitement

Inscrivez-vous à notre newsletter DevOps

Thank you for signing up