Close

Integracja Concourse-ci i Atlassian Open DevOps

Wiele zespołów wdraża własne narzędzia w celu zaspokojenia swoich potrzeb lub od lat korzysta ze starszych narzędzi. Te narzędzia mają zasadnicze znaczenie dla przyjętego w zespole przebiegu prac programistycznych, ale nie mają gotowych integracji z Jira. Na szczęście niestandardową integrację można łatwo utworzyć przy użyciu interfejsów API REST Atlassian dostępnych na stronie Cloud developer documentation - Atlassian Developer. Concourse-ci to produkt CI/CD, dla którego w momencie pisania tego artykułu w sklepie Atlassian Marketplace nie ma dostępnej integracji. W tym artykule przedstawiono sposób utworzenia podstawowej integracji między Jira i Concourse-ci przy użyciu interfejsów API REST Atlassian.

Wymagania wstępne

Użyj niezbędnej dokumentacji, aby skonfigurować narzędzia Docker, docker-compose i Concourse-ci. Concourse-ci działa na platformie Docker i udostępnia skrypt docker-compose w celu uproszczenia rozpoczęcia pracy.

Przeczytaj o aplikacji demonstracyjnej ImageLabeller firmy Atlassian tutaj. W tym artykule przedstawiono, jak używać Concourse-ci w celu wdrożenia komponentu SubmitImage aplikacji ImageLabeller w AWS.

Docker

Skonfiguruj narzędzia Docker i docker-compose, postępując zgodnie z ich dokumentacją:

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

Concourse-ci

Po zainstalowaniu narzędzi Docker i docker-compose możesz uruchomić Concourse-ci za pomocą dostarczonego pliku docker-compose.yml.

Aby zacząć korzystać z Concourse-ci, postępuj zgodnie ze skróconym przewodnikiem dostępnym pod adresem https://concourse-ci.org/quick-start.html#docker-compose-concourse. Ten przewodnik wymaga bezpiecznego przekazania poświadczeń do Concourse-ci. W tym celu w przewodniku przedstawiono integrację Concourse-ci z AWS Secrets Manager.

Integracja Concourse-ci z AWS Secrets Manager

Tutaj znajdziesz dokumentację dotyczącą integracji Concourse-ci z AWS Secrets Manager. Postępuj zgodnie ze wskazówkami podanymi w dokumentacji, aby uruchomić integrację i rozpocząć.

Plik docker-compose.yml, który jest używany do uruchomienia Concourse-ci, wymaga nieznacznej modyfikacji, aby integracja zadziałała. Do domyślnego pliku docker-compose.yml dostarczonego przez Concourse-ci dodaj
CONCOURSE_AWS_SECRETSMANAGER_ACCESS_KEY, CONCOURSE_AWS_SECRETSMANAGER_SECRET_KEY i 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>

Po skonfigurowaniu integracji i uruchomieniu Concourse-ci z włączoną integracją dodaj poniższe klucze tajne do 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

Klucze tajne Bitbucket i Docker mogą wymagać zastąpienia, jeśli nie używasz rozwiązania Bitbucket do zarządzania swoim kodem ani JFrog jako repozytorium Docker. Dostosowanie tych ustawień do indywidualnego zestawu narzędzi pozostawiamy jako ćwiczenie.

klucze tajne bitbucket i docker

Praca z Concourse-ci

Uruchom polecenie docker ps -a przed i po uruchomieniu polecenia docker-compose up -d, aby sprawdzić, czy narzędzie Concourse-ci zostało poprawnie uruchomione.

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

Przejdź pod adres http://localhost:8080/ po uruchomieniu polecenia 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

W tej chwili nie ma zdefiniowanych żadnych pipeline'ów.

Pipeline hello world

Skonfiguruj pipeline hello world, postępując zgodnie z tą dokumentacją Concourse-ci: https://concourse-ci.org/tutorial-hello-world.html. Jest to konieczne, aby przedstawić narzędzie fly CLI i przyzwyczaić się do pracy z Concourse-ci z poziomu wiersza polecenia.

W następnej części pokazano, jak wdrożyć platformę AWS Lambda napisaną w języku Golang w pojedynczym regionie AWS za pomocą Concourse-ci i jak napisać aktualizację zgłoszenia Jira w ramach tego procesu.

Wdrożenie SubmitImage za pomocą Concourse-ci

Wdrożenie SubmitImage Lambda przy użyciu Concourse-ci odbywa się w trzech krokach. Pierwszym krokiem jest napisanie prostego skryptu bash wykorzystującego interfejs API REST Jira Cloud w celu napisania komentarza w zgłoszeniu Jira. Jest to najprostsza integracja, którą możemy utworzyć. Drugim krokiem jest utworzenie obrazu Docker z niezbędnymi narzędziami oraz wdrożenie Golang AWS Lambda. Ostatnim krokiem jest napisanie dwóch plików konfiguracyjnych Concourse-ci. Pierwszy plik konfiguracyjny, parent.yml, monitoruje repozytorium SubmitImage pod kątem nowych gałęzi i przygotowuje nowe pipeline'y w celu wdrożenia commitów z tych gałęzi. Drugi plik konfiguracyjny, child.yml, definiuje zestaw kroków niezbędnych do wdrożenia zmiany.

Krok 1 — aktualizowanie zgłoszeń Jira za pośrednictwem interfejsu API REST

Ten skrypt aktualizacji używa interfejsu API REST platformy Jira Cloud do napisania komentarza do konkretnego zgłoszenia Jira. Istnieje pięć wymaganych parametrów, które należy ustawić za każdym razem, gdy uruchamiany jest skrypt. Elementy jiraUsername, jiraApiToken i workspace są zazwyczaj takie same dla każdego uruchomienia określonego pipeline'u. Z kolei issueKey będzie zależeć od nazwy gałęzi, która jest wdrażana. Najlepszą praktyką Jira jest, aby podczas pracy nad konkretnym zgłoszeniem umieszczać identyfikator zgłoszenia Jira w nazwach gałęzi i komunikatach dotyczących commita. W tym artykule przyjęto założenie, że przestrzegane są najlepsze praktyki, a nazwy gałęzi są tożsame z identyfikatorami zgłoszenia Jira.

Jak znaleźć parametry
Nazwa użytkownika Jira


Nazwa użytkownika Jira to adres e-mail używany do logowania się do systemu Jira.

Token API Jira
Przejdź do opcji Ustawienia konta

Ustawienia konta — tokeny API Jira

Kliknij opcję Bezpieczeństwo.

bezpieczeństwo konta

Kliknij Utwórz tokeny API i zarządzaj nimi

Przestrzeń robocza

Dla następującego adresu URL instancji Jira https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 przestrzeń robocza to pmmquickstartguide01.

Klucz zgłoszenia

Dla następującego adresu URL zgłoszenia Jira https://pmmquickstartguides01.atlassian.net/jira/software/projects/IM/boards/1?selectedIssue=IM-203 klucz zgłoszenia Jira to IM-203. Umieść identyfikator zgłoszenia Jira w komunikatach dotyczących commita i nazwach gałęzi, aby integracja mogła zapisywać aktualizacje we właściwej lokalizacji.

Komentarz

Komentarz może mieć dowolną postać.

Skrypt aktualizacji

Skrypt aktualizacji jest prostym skryptem powłoki bash wykorzystującym punkt końcowy interfejsu API REST komentarza do zgłoszenia Jira. Tutaj znajduje się dokumentacja tego wywołania interfejsu API. Skrypt można zmodyfikować w celu zapewnienia ściślejszej integracji, korzystając z podanego wzorca wykonywania dodatkowych wywołań interfejsu API. Skopiuj ten skrypt do pliku o nazwie concourse-ci-integration.sh i umieść go w repozytorium Bitbucket lub GitHub o nazwie 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 "$@"

Krok 2 — niestandardowy plik Dockerfile

Utwórz niestandardowy plik Dockerfile za pomocą narzędzi potrzebnych do skompilowania i wdrożenia platformy AWS Lambda napisanej w języku Golang. Dockerfile instaluje niektóre narzędzia, a następnie dodaje AWS SAM i Golang. System Git obrazu klonuje skrypt aktualizacji utworzony w kroku 1 z repozytorium Bitbucket. Musisz zastąpić to repozytorium Bitbucket jakimkolwiek repozytorium utworzonym do przechowywania skryptu aktualizacji. Docker kompiluje ten plik Dockerfile i wypycha go do repozytorium 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

Krok 3 — pliki yaml pipeline'u wdrażania Concourse-ci

Utwórz nowe repozytorium o nazwie concourse i umieść w nim dwa pliki. Parent.yml tworzy pipeline do monitorowania repozytorium pod kątem nowych gałęzi, które pasują do wyrażenia regularnego. Wyrażenie regularne (branch_regex), które pasuje do wszystkich gałęzi zaczynających się od IM-, to IM-*. Parent.yml utworzy nowy pipeline za pomocą konfiguracji w pliku child.yml, gdy zostanie utworzona nowa gałąź, która pasuje do wyrażenia regularnego IM-*. Zaktualizuj ten plik, aby wskazywał na Twoją wersję repozytorium SubmitImage. Kod SubmitImage znajduje się tutaj. Skopiuj ten kod z repozytorium do repozytorium z uprawnieniami do zapisu.

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 definiuje pipeline z czterema krokami. Najpierw uruchamia polecenie sam validate, aby sprawdzić, czy plik template.yml usługi AWS CloudFormation jest prawidłowy. Następnie uruchamia polecenie sam build, aby z pakietu SubmitImage utworzyć artefakt możliwy do wdrożenia. W kolejnym etapie uruchamia polecenie sam deploy, aby wdrożyć zaktualizowany kod SubmitImage w AWS. Na końcu pipeline wywołuje skrypt aktualizacji utworzony w kroku 1, aby napisać komentarz w pasującym zgłoszeniu 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"]

Uruchamianie pipeline'u nadrzędnego

Uruchom trzy ponizsze polecenia z katalogu z plikem parent.yml. Pierwsze polecenie loguje się do lokalnie uruchomionej instancji Concourse-ci. Drugie polecenie tworzy pipeline o nazwie wm na podstawie konfiguracji w pliku parent.yml. Trzecie polecenie wyłącza wstrzymanie pipeline'u 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

Po uruchomieniu tych trzech poleceń przejdź do klienta internetowego Concourse-ci, aby zobaczyć, czy pipeline wm jest uruchomiony.

obraz klienta internetowego Concourse-ci

Po uruchomieniu polecenia fly set-pipeline z użyciem pliku parent.yml jest tworzony pipeline wm. Ten pipeline monitoruje SubmitImage pod kątem nowych gałęzi funkcji i tworzy pipeline dla każdej gałęzi funkcji pasującej do wyrażenia regularnego w pliku parent.yml.

fly set pipeline

Kliknij pipeline wm, aby zobaczyć kroki, które są uruchomione. Zwróć uwagę, że krok feature-branches zawiera gałąź IM-61. Jest to jedyna gałąź istniejąca obecnie w SubmitImage, która pasuje do wyrażenia regularnego w pliku parent.yml. Kliknij automatycznie włączony pipeline dev, aby zobaczyć uruchomione przez niego kroki.

Pipeline wm po poleceniu fly set pipeline

Zauważ, że jest tam krok pobierania repozytorium SubmitImage i że gałąź to IM-61. Zwróć też uwagę, że są tam kroki run-sam-validate, run-sam-build, run-sam-deploy i run-update-script.

Podsumowanie zgłoszenia Jira IM-61

Po zakończeniu działania pipeline'u dev wróć do zgłoszenia Jira IM-61 i zwróć uwagę, że minutę temu zarejestrowano nowy komentarz, który pasuje do ciągu komentarza z pliku child.yml

Wnioski…

W tym przewodniku pokazano, jak skonfigurować pipeline w celu automatycznego wdrożenia Golang AWS Lambda w pojedynczym regionie AWS za pomocą Concourse-ci. Przedstawiono również, jak używać skryptu powłoki bash do napisania prostej integracji z systemem Jira. Skrypt integracji można znacznie rozszerzyć dzięki szczegółowym informacjom zawartym w dokumentacji interfejsu API REST Atlassian dostępnej tutaj.

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.

Udostępnij ten artykuł

Zalecane lektury

Dodaj te zasoby do zakładek, aby dowiedzieć się więcej na temat rodzajów zespołów DevOps lub otrzymywać aktualności na temat metodyki DevOps w Atlassian.

Ilustracja DevOps

Społeczność DevOps

Ilustracja DevOps

Ścieżka szkoleniowa DevOps

Ilustracja przedstawiająca mapę

Zacznij korzystać za darmo

Zapisz się do newslettera DevOps

Thank you for signing up