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.
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
Klicke auf Sicherheit
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.
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.
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.
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".
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.
Diesen Artikel teilen
Nächstes Thema
Lesenswert
Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.