Runners Program Runners umożliwia uruchamianie kompilacji w Pipelines we własnej infrastrukturze i nie zostanie naliczona opłata za minuty kompilacji wykorzystane przez samodzielnie hostowanych runnerów. Poniższe przewodniki pomagają skonfigurować system operacyjny za pomocą Pipelines, aby używać modułów uruchamiających w repozytoriach.

Obsługiwane platformy

  1. Linux z architekturą x64 i jądrem Linux 4.0.0+. Runery zostały przetestowane na następujących dystrybucjach Linuksa:
  2. Windows 10+ lub Windows Server 2019+
  3. MacOS Catalina 10.15+

Minimalne wymagania

Doker Linuksa:

  1. 64-bitowa instancja Linux z co najmniej 8 GB pamięci RAM jako hostem dla runnera.
  2. Docker v19.03 i nowsze

Bitbucket Pipelines umożliwia tworzenie obrazu platformy Docker z pliku Docker w repozytorium i wypychanie go do rejestru platformy Docker przez uruchamianie poleceń platformy Docker w potoku kompilacji. Zanurz się prosto – środowisko potoku jest dostarczane domyślnie i nie musisz go dostosowywać!

Włączenie dostepu do Dockerza Aby umożliwić dostęp do demona Docker, można dodać dockera jako usługę w kroku lub dodać opcję globalną w pliku bitbucket-pipelines.yml.

Żeby skonfigurować Bitbucket Runners komendami ze strony Docker Linux należy: Pierwszy ze sposobów:

  1. Wyłączyć swap w środowisku Linux

Poniżej znajdują się kroki, aby wyłączyć swap dla większości dystrybucji Linuksa . Jeśli poniższe polecenia nie są zainstalowane, będziesz musiał je zainstalować. Zapoznaj się z dokumentacją dystrybucji, aby skonfigurować swap.

1
sudo swapon -sv

Jeśli zamiana jest włączona, powinieneś zobaczyć dane wyjściowe podobne do następujących:

1
2
NAME      TYPE      SIZE   USED PRIO
/dev/sda3 partition   2G 655.2M   -1
  1. Jeśli zamiana jest włączona, będziesz musiał ją wyłączyć

  2. Skonfiguruj vm.swappiness w środowisku Linux

Poniżej znajdują się kroki, aby skonfigurować vm.swappiness dla większości dystrybucji Linuksa . Jeśli poniższe polecenia nie są zainstalowane, będziesz musiał je zainstalować. Zapoznaj się z dokumentacją dystrybucji, aby skonfigurować swap.

Użyj następującego polecenia, aby sprawdzić wartość vm.swappiness:

1
sudo sysctl -n vm.swappiness

Jeśli wartość swappiness jest inna niż 1 , skonfiguruj ją za pomocą następującego procesu: Uruchom następujące polecenie, upewniając się, że dane wyjściowe są teraz 1:

1
sudo sysctl -n vm.swappiness

Drugi ze sposobów: Ten sposób jest o wiele prostszy. Polega on na tym, że Bitbucket Runners wydaje polecenie, które trzeba po prostu uruchomić w konsoli Linux. Polecenie wygladą nastepująco:

Copy this command with the token to run on the command line

1
docker container run -it -v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/containers:/var/lib/docker/containers:ro -e ACCOUNT_UUID={c09fffc4-c0e4-4c0d-bd98-ef23d2aa6dca} -e REPOSITORY_UUID={49ca6428-767f-4f57-95ec-84cb0fd05c08} -e RUNNER_UUID={4b3b8bf3-c323-536f-b2ba-797e0aa721b9} -e RUNTIME_PREREQUISITES_ENABLED=true -e OAUTH_CLIENT_ID=sLwWKhotz990WnKjNhNK1ouD5HKKkA9I -e OAUTH_CLIENT_SECRET=8MEOpdDBBFpwENUr518EcEUJWHZFiIh3miEu1OzmZ2AyWMSkB0wCrpdbA9ElfpxC -e WORKING_DIRECTORY=/tmp --name runner-4b3b8bf3-c323-536f-b2ba-797e0aa721b9 docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner:1

Po czym konfiguracja pliku bitbucket-pipelines.yml tworzy się samodzielnie:

1
2
3
4
5
6
7
pipelines:
  default:
      - step:
          runs-on:
            - self.hosted
            - linux
          script:
1
2
3
4
5
6
**Notatka**
Jeśli nie określisz etykiety linux.shell, nasz program planujący przyjmie, że jest to krok Linux Docker i spróbuje uruchomić go jako Linux Docker Runner.

Jeśli wszystkie pasujące Linux Shell Runners  zajęte, Twój krok zostanie umieszczony w kolejce, dopóki jeden nie stanie się ponownie dostępny.

Jeśli nie masz w swoim repozytorium żadnych biegaczy online, które pasują do wszystkich Twoich etykiet, krok się nie powiedzie.

Jak stworzyć Runner?

Utwórz nowy Workspace Runner w Bitbucket

Przejdź do ustawień obszaru roboczego

Kliknij swoje zdjęcie profilowe i wybierz obszar roboczy

Photo

Kliknij Ustawienia i przewiń w dół do Workspace Runners i kliknij Dodaj Runnera:

Photo

Nadaj swojemu biegaczowi imię i kliknij Dalej.

Photo

To da ci wynik polecenia taki:

1
2
3
4
5
6
7
8
9
docker container run -it -v /tmp:/tmp -v /var/run/docker.sock:/var/run/docker.sock \
  -v /var/lib/docker/containers:/var/lib/docker/containers:ro \
  -e ACCOUNT_UUID={__ACCOUNT_UUID__} \
  -e RUNNER_UUID={__RUNNER_UUID__} \
  -e OAUTH_CLIENT_ID=__OAUTH_CLIENT_ID__ \
  -e OAUTH_CLIENT_SECRET=__OAUTH_CLIENT_SECRET__ \
  -e WORKING_DIRECTORY=/tmp \
  --name runner-7deb7740-f86b-50d0-9c85-671fcb3c9038 \
  docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner:1

Zapisz go i kliknij Zakończ.

Musisz wyodrębnić zmienne ACCOUNT_UUID, RUNNER_UUID, OAUTH_CLIENT_ID i OAUTH_CLIENT_SECRET z polecenia.

Uważaj na następujące rzeczy:

  • Skopiuj ACCOUNT_UUID i RUNNER_UUID bez nawiasów klamrowych.
  • Pamiętaj, aby skopiować cały OAUTH_CLIENT_SECRET (może zawierać znaki specjalne, takie jak myślniki lub podkreślenia).
  • Zmienne OAUTH muszą zostać przekonwertowane na base64.

Możesz wypełnić następujący skrypt, a później wygenerować zasoby k8s za pomocą tych zmiennych:

1
2
3
4
5
6
7
export ACCOUNT_UUID=__ACCOUNT_UUID__
export RUNNER_UUID=__RUNNER_UUID__
export OAUTH_CLIENT_ID=__OAUTH_CLIENT_ID__
export OAUTH_CLIENT_SECRET=__OAUTH_CLIENT_SECRET__

export BASE64_OAUTH_CLIENT_ID=$(echo -n $OAUTH_CLIENT_ID | base64)
export BASE64_OAUTH_CLIENT_SECRET=$(echo -n $OAUTH_CLIENT_SECRET | base64)

Wdrożenie w Kubernetes

Teraz interesująca część. Zastąp symbole zastępcze ${VAR_NAME} zawartością tych zmiennych.

Ważne:

  • użyj zakodowanych w base64 wersji zmiennych OAUTH w pliku secret.yaml
  • zachowaj cudzysłowy i nawiasy klamrowe („, {, }”) w liniach job.yaml 17 i 19

Następujące skrypty bash wygenerują pliki secret.yaml i job.yaml w bieżącym katalogu roboczym.

secret.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
cat > ./secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: runner-oauth-credentials
  labels:
    accountUuid: ${ACCOUNT_UUID}
    runnerUuid: ${RUNNER_UUID}
data:
  oauthClientId: ${BASE64_OAUTH_CLIENT_ID}
  oauthClientSecret: ${BASE64_OAUTH_CLIENT_SECRET}
EOF

job.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
cat > ./job.yaml <<EOF
apiVersion: batch/v1
kind: Job
metadata:
  name: runner
spec:
  template:
    metadata:
      labels:
        accountUuid: ${ACCOUNT_UUID}
        runnerUuid: ${RUNNER_UUID}
    spec:
      containers:
        - name: bitbucket-k8s-runner
          image: docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner
          env:
            - name: ACCOUNT_UUID
              value: "{${ACCOUNT_UUID}}"
            - name: RUNNER_UUID
              value: "{${RUNNER_UUID}}"
            - name: OAUTH_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: runner-oauth-credentials
                  key: oauthClientId
            - name: OAUTH_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: runner-oauth-credentials
                  key: oauthClientSecret
            - name: WORKING_DIRECTORY
              value: "/tmp"
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: docker-containers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: var-run
              mountPath: /var/run
        - name: docker-in-docker
          image: docker:20.10.7-dind
          securityContext:
            privileged: true
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: docker-containers
              mountPath: /var/lib/docker/containers
            - name: var-run
              mountPath: /var/run
      restartPolicy: OnFailure
      volumes:
        - name: tmp
        - name: docker-containers
        - name: var-run
  backoffLimit: 6
  completions: 1
  parallelism: 1
EOF

job.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
cat > ./job.yaml <<EOF
apiVersion: batch/v1
kind: Job
metadata:
  name: runner
spec:
  template:
    metadata:
      labels:
        accountUuid: ${ACCOUNT_UUID}
        runnerUuid: ${RUNNER_UUID}
    spec:
      containers:
        - name: bitbucket-k8s-runner
          image: docker-public.packages.atlassian.com/sox/atlassian/bitbucket-pipelines-runner
          env:
            - name: ACCOUNT_UUID
              value: "{${ACCOUNT_UUID}}"
            - name: RUNNER_UUID
              value: "{${RUNNER_UUID}}"
            - name: OAUTH_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: runner-oauth-credentials
                  key: oauthClientId
            - name: OAUTH_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: runner-oauth-credentials
                  key: oauthClientSecret
            - name: WORKING_DIRECTORY
              value: "/tmp"
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: docker-containers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: var-run
              mountPath: /var/run
        - name: docker-in-docker
          image: docker:20.10.7-dind
          securityContext:
            privileged: true
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: docker-containers
              mountPath: /var/lib/docker/containers
            - name: var-run
              mountPath: /var/run
      restartPolicy: OnFailure
      volumes:
        - name: tmp
        - name: docker-containers
        - name: var-run
  backoffLimit: 6
  completions: 1
  parallelism: 1
EOF

Zastosuj wygenerowane manifesty do Kubernetes:

1
2
3
kubectl create namespace bitbucket-runner --dry-run -o yaml | kubectl apply -f -
kubectl -n bitbucket-runner apply -f secrets.yaml
kubectl -n bitbucket-runner apply -f job.yaml

Jeśli wszystko poszło dobrze, wkrótce zobaczysz biegacza ze statusem ONLINE na stronie Workspace Runners.

Photo

Jeśli zdecydujesz się usunąć biegacza z Kubernetes, wykonaj następujące kroki:

1
2
3
kubectl -n bitbucket-runner delete -f job.yaml            
kubectl -n bitbucket-runner delete -f secret.yaml 
kubectl delete namespace bitbucket-runner

Jak używać tego runnera w potoku Bitbucket?

To całkiem proste, dodaj etykiety runnera do etapu potoku.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pipelines:
  custom:
    pipeline:
      - step:
          name: Step1
          size: 8x # default 4gb, 8x for 32gb
          runs-on: 
            - 'self.hosted'
            - 'my.custom.label'
          script:
            - echo "This step will run on a self hosted runner with 32 GB of memory.";
      - step:
          name: Step2
          script:
            - echo "This step will run on Atlassian's infrastructure as usual.";

Błąd: status 500 w potokach Bitbucket

Ponieważ chcieliśmy zbudować obrazy Dockera (za pomocą Dockera w Dockerze lub dind) w naszym potoku, napotkaliśmy następujący problem:

1
Status 500: {"message":"io.containerd.runc.v2: failed to adjust OOM score for shim: set shim OOM score: write /proc/PROC_ID/oom_score_adj: invalid argument\n: exit status 1: unknown"}

Jak to naprawić

Najpierw próbowałem znaleźć główną przyczynę tego komunikatu o błędzie, ale nie mogłem znaleźć niczego poza kilkoma komentarzami na ten temat, które zostały już naprawione w ostatnim wydaniu containerd, i tak dalej… Postanowiłem więc sprawdzić, czy wersje oprogramowania się zgadzają. Nawet gdy containerd pasował do wymaganej wersji, stwierdziłem, że Docker na serwerach jest nieco przestarzały (19.03), więc postanowiłem go zaktualizować.

Po aktualizacji nadal widziałem wcześniej wspomniane komunikaty o błędach w potokach Bitbucket.

Zweryfikowałem wersję Dockera uruchomioną na serwerze:

1
2
# docker --version    
Docker version 20.10.7, build f0df350   

Wymieniłem docker w wersji obrazu kontenera docker (dind), aby używał dokładnie tej samej wersji, co zainstalowana w naszym klastrze k8s!

1
2
- name: docker-in-docker
  image: docker:20.10.5-dind  ->  docker:20.10.7-dind

I magicznie błąd zniknął i wszystko działa zgodnie z oczekiwaniami.