Close

Concourse-CI und Atlassian Open DevOps integrieren

Viele Teams entwickeln eigene Tools, die ihre Anforderungen erfüllen, oder haben bereits seit Jahren dieselben Tools im Einsatz. Diese Tools sind für den Entwicklungsprozess eines Teams unverzichtbar, lassen sich aber nicht ohne Weiteres in Jira integrieren. Zum Glück ist es ganz einfach, mithilfe der Atlassian REST-APIs eine benutzerdefinierte Integration zu erstellen. Mehr dazu findest du in der Cloud-Entwicklerdokumentation – Atlassian Developer. Concourse-CI ist ein CI/CD-Produkt, für das zum aktuellen Zeitpunkt noch keine Integration im Atlassian Marketplace verfügbar ist. In diesem Artikel erfährst du, wie du mit den Atlassian REST-APIs eine einfache Integration zwischen Jira und Concourse-CI erstellst.

Voraussetzungen

Befolge die jeweilige Dokumentation, um Docker, docker-compose und Concourse-CI einzurichten. Concourse-CI wird auf Docker ausgeführt. Ein docker-compose-Skript erleichtert dir die ersten Schritte.

Weitere Informationen zur Demo-Anwendung "ImageLabeller" von Atlassian findest du hier. In diesem Artikel erfährst du, wie du Concourse-CI verwendest, um die SubmitImage-Komponente von ImageLabeller auf AWS bereitzustellen.

Docker

Richte Docker und docker-compose ein, indem du die zugehörige Dokumentation befolgst:

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

Concourse-CI

Wenn du Docker und docker-compose installiert hast, kannst du Concourse-CI starten, indem du die bereitgestellte Datei docker-compose.yml verwendest.

Befolge die Concourse-CI-Kurzanleitung unter https://concourse-ci.org/quick-start.html#docker-compose-concourse, um loszulegen. Dieser Leitfaden erfordert die sichere Übertragung von Anmeldeinformationen an Concourse-CI. Dafür verwenden wir die Concourse-CI AWS Secrets Manager-Integration.

Concourse-CI-mit AWS Secrets Manager integrieren

Hier findest du die Dokumentation zur Integration von Concourse-CI mit AWS Secrets Manager. Befolge die Anweisungen zur Integration aus der Dokumentation.

Die Datei "docker-compose.yml", die du zum Ausführen von Concourse-CI verwendest, muss etwas abgeändert werden, damit die Integration funktioniert. Verwende die von Concourse-CI bereitgestellte Standarddatei "docker-compose.yml" und füge Folgendes hinzu:
CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY, CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY und 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>

Wenn die Integration eingerichtet ist und Concourse-CI mit aktivierter Integration ausgeführt wird, füge die folgenden geheimen Schlüssel zu AWS Secrets Manager hinzu:

/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

Die geheimen Schlüssel für Bitbucket und Docker müssen möglicherweise ersetzt werden, wenn der Leser für den Code nicht Bitbucket bzw. JFrog als Docker-Repository verwendet. Es ist dir überlassen, das an die individuellen Tools des Lesers anzupassen.

Geheime Bitbucket- und Docker-Schlüssel

Concourse-CI verwenden

Führe "docker ps -a" aus, bevor und nachdem du "docker-compose up -d" verwendest, um zu sehen, ob Concourse-CI erfolgreich startet.

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

Rufe http://localhost:8080/ auf, nachdem du Folgendes ausgeführt hast: "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

Derzeit sind keine Pipelines definiert.

Eine "Hello World"-Pipeline

Richte eine "Hello World"-Pipeline ein, indem du diese Concourse-CI-Dokumentation befolgst: https://concourse-ci.org/tutorial-hello-world.html. Das ist erforderlich, um die Fly-CLI einzuführen und damit du dich daran gewöhnst, in Concourse-CI die Befehlszeile zu verwenden.

Im nächsten Abschnitt erfährst du, wie du mit Concourse-CI ein in Golang geschriebenes AWS Lambda für eine einzelne AWS-Region bereitstellst. Außerdem findest du heraus, wie du als Teil des Prozesses ein Update für einen Jira-Vorgang erstellst.

SubmitImage mit Concourse-CI bereitstellen

Um SubmitImage Lambda mit Concourse-CI bereitzustellen, sind drei Schritte erforderlich. Im ersten Schritt schreibst du ein einfaches Bash-Skript, das die Jira Cloud REST-API verwendet, um in einem Jira-Vorgang einen Kommentar zu erstellen. Das ist die einfachste Integration, die man erstellen kann. Im zweiten Schritt erstellst du ein Docker-Image, das über die erforderlichen Tools zum Erstellen und Bereitstellen eines Golang AWS Lambda verfügt. Im letzten Schritt schreibst du zwei Concourse-CI-Konfigurationsdateien. Die erste Konfigurationsdatei – "parent.yml" – überwacht das SubmitImage-Repository hinsichtlich neuer Branches und richtet neue Pipelines ein, um Commits von diesen Branches bereitzustellen. Die zweite Konfigurationsdatei – "child.yml" – definiert die erforderlichen Schritte, um eine Änderung bereitzustellen.

1. Schritt – Jira-Vorgänge über die REST-API aktualisieren

Dieses Aktualisierungsskript verwendet die REST-API der Jira Cloud-Plattform, um einen Kommentar zu einem bestimmten Jira-Vorgang zu erstellen. Es gibt fünf erforderliche Parameter, die jedes Mal festgelegt werden müssen, wenn das Skript ausgeführt wird. Die Parameter "jiraUsername", "jiraApiToken" und "workspace" bleiben normalerweise für jede Ausführung einer bestimmten Pipeline gleich. Der Parameter "issueKey" hängt vom Namen des jeweiligen bereitgestellten Branches ab. Es ist eine Best Practice in Jira, die Jira-Vorgangs-ID in den Namen der Branches einzufügen und Nachrichten zu committen, wenn du an einem bestimmten Vorgang arbeitest. In diesem Artikel gehen wir davon aus, dass du die Best Practice befolgst und die Namen der Branches mit der Jira-Vorgangs-ID übereinstimmen.

So findest du die Parameter
Jira-Benutzername


Der Jira-Benutzername ist die E-Mail-Adresse, mit der du dich bei Jira anmeldest.

Jira-API-Token
Rufe Kontoeinstellungen auf

JIRA API-Token – Kontoeinstellungen

Klicke auf Sicherheit

Kontosicherheit

Klicke auf API-Token erstellen und verwalten

Arbeitsbereich

Bei einer Jira-Instanz-URL wie https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 lautet der Arbeitsbereich pmmquickstartguide01.

Vorgangsschlüssel

Bei einer Jira-Vorgangs-URL wie https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 lautet der Jira-Vorgangsschlüssel IM-203. Füge die Jira-Vorgangs-ID in Commit-Nachrichten und Branch-Namen ein, damit die Integration am richtigen Speicherort Aktualisierungen schreiben kann.

Kommentar

Als Kommentar kannst du alles Mögliche eingeben.

Das Aktualisierungsskript

Das Aktualisierungsskript ist ein einfaches Bash-Shell-Skript, das den REST-API-Endpunkt des Jira Vorgangs-Kommentars verwendet. Hier findest du die Dokumentation für diesen API-Aufruf. Du kannst das Skript anpassen, um eine verbesserte Integration zu ermöglichen, indem du für zusätzliche API-Aufrufe die angegebenen Schritte befolgst. Kopiere dieses Skript in eine Datei namens concourse-ci-integration.sh und füge sie zum Bitbucket- oder GitHub-Repository updateScript hinzu.

#!/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. Schritt – Benutzerdefiniertes Dockerfile

Erstelle mit den erforderlichen Tools zum Erstellen und Bereitstellen eines in Golang geschriebenen AWS Lambda ein benutzerdefiniertes Dockerfile. Durch das Dockerfile werden einige Dienstprogramme installiert und anschließend AWS SAM und Golang hinzugefügt. Durch das Image-Git wird das im ersten Schritt aus einem Bitbucket-Repository erstellte Aktualisierungsskript geklont. Du musst dieses Bitbucket-Repository durch das entsprechende Repository ersetzen, das du für das Aktualisierungsskript erstellt hast. Erstelle dieses Dockerfile mit Docker und verschiebe es in ein Docker-Repository.

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. Schritt – yaml-Dateien der Concourse-CI-Deployment-Pipeline

Erstelle ein neues Repository namens "concourse" und füge zwei Dateien hinzu. Durch Parent.yml wird eine Pipeline erstellt. Diese überwacht ein Repository hinsichtlich neuer Branches, die mit einem Regex übereinstimmen. Der branch_regex lautet IM-*. Er liefert alle Branches, die mit IM- beginnen. Wenn es einen neuen Branch gibt, der mit dem Regex IM-* übereinstimmt, wird durch "parent.yml" mit der Konfiguration "child.yml" eine neue Pipeline erstellt. Du solltest diese Datei so aktualisieren, dass sie auf deine eigene Version des SubmitImage-Repositorys verweist. Den SubmitImage-Code findest du hier. Kopiere den Code dieses Repositorys in ein Repository mit Schreibberechtigungen.

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

Mit "child.yml" wird eine Pipeline in vier Schritten definiert. Zuerst wird "sam validate" ausgeführt, um zu überprüfen, ob die AWS CloudFormation-Datei "template.yml" gültig ist. Anschließend wird "sam build" ausgeführt, um das SubmitImage-Paket in ein bereitstellbares Artefakt umzuwandeln. Als Nächstes wird "sam deploy" ausgeführt, um den aktualisierten SubmitImage-Code auf AWS bereitzustellen. Letztendlich wird durch die Pipeline das im ersten Schritt erstellte Aktualisierungsskript aufgerufen, damit ein Kommentar zum entsprechenden Jira-Vorgang geschrieben werden kann.

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

So startest du die parent-Pipeline

Führe mit "parent.yml" die folgenden drei Befehle im Verzeichnis aus. Durch den ersten Befehl wird eine Anmeldung in der lokal ausgeführten Concourse-CI-Instanz durchgeführt. Durch den zweiten Befehl wird eine Pipeline namens "wm" erstellt, die auf der Konfiguration in "parent.yml" basiert. Durch den dritten Befehl wird die "wm"-Pipeline fortgesetzt.

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

Nachdem du diese drei Befehle ausgeführt hast, rufe den Concourse-CI-Webclient auf, um zu sehen ob die "wm"-Pipeline ausgeführt wird.

Bild: Concourse CI-Webclient

Nachdem fly set-pipeline für "parent.yml" ausgeführt wurde, ist eine "wm"-Pipeline vorhanden. Diese Pipeline überwacht SubmitImage hinsichtlich neuer Feature-Branches und erstellt eine Pipeline für jeden Feature-Branch, der mit dem Regex in "parent.yml" übereinstimmt.

fly set-Pipeline

Klicke auf die "wm"-Pipeline, um die Schritte zu sehen, die ausgeführt werden. Beachte, dass im Feature-Branch-Schritt ein "IM-61"-Branch aufgelistet ist. Das ist derzeit der einzige Branch in SubmitImage, der mit dem Regex in "parent.yml" übereinstimmt. Klicke auf die automatisch gestartete "dev"-Pipeline, um zu sehen, welche Schritte ausgeführt werden.

wm-Pipeline nach "fly set-pipeline"

Du siehst, dass es einen Schritt zum Erstellen des SubmitImage-Repositorys gibt und dass der Branch "IM-61" lautet. Übrigens gibt es auch die Schritte "run-sam-validate", "run-sam-build", "run-sam-deploy" und "run-update-script".

Zusammenfassung IM 61-Jira-Vorgang

Wenn die "dev"-Pipeline ausgeführt wurde, rufe erneut den IM-61-Jira-Vorgang auf. Du wirst feststellen, dass vor einer Minute ein neuer Kommentar erfasst wurde, der mit dem Kommentar-String von "child.yml" übereinstimmt.

Fazit

In diesem Leitfaden erfährst du, wie du eine Pipeline einrichtest, um mit Concourse-CI automatisch ein Golang AWS Lambda für eine einzelne AWS-Region bereitzustellen. Wir erklären auch, wie du ein Bash-Shell-Skript verwendest, um mit Jira eine einfache Integration zu erstellen. Das Integrationsskript kann umfassend erweitert werden. Informiere dich dazu in der Atlassian REST-API-Dokumentation.

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.

Diesen Artikel teilen

Lesenswert

Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.

Abbildung: DevOps

DevOps-Community

Abbildung: DevOps

DevOps-Lernpfad

Abbildung: Karte

Kostenlos loslegen

Melde dich für unseren DevOps-Newsletter an

Thank you for signing up