Rura wielogałęziowa Jenkinsa w GKE

1. Omówienie

Jenkins to jedno z najpopularniejszych dostępnych rozwiązań ciągłej integracji. Służy on do automatyzacji kluczowych elementów procesu tworzenia oprogramowania, które nie wymagają udziału człowieka. Dzięki wdrożeniu Jenkinsa w Kubenetes w Google Cloud i użyciu wtyczki GKE możemy szybko i automatycznie skalować wykonawców kompilacji w razie potrzeby. W połączeniu z Cloud Storage możemy tworzyć i testować aplikacje z minimalnym wysiłkiem.

Co musisz zrobić

  • Wdrażanie usługi Jenkins w klastrze Kubernetes
  • Wdróż i skonfiguruj wtyczkę Jenkins GKE, aby umożliwić Jenkinsowi tworzenie i usuwanie podów jako węzłów wykonawczych.
  • Kompilowanie i testowanie przykładowej aplikacji SpringBoot
  • Tworzenie i publikowanie kontenera w Google Container Registry
  • Wdrażanie przykładowej aplikacji w środowisku testowym i produkcyjnym GKE

Czego potrzebujesz

  • projekt Google Cloud z skonfigurowanymi rozliczeniami, Jeśli go nie masz, musisz je utworzyć.

2. Konfiguracja

To Codelab może działać całkowicie w Google Cloud Platform bez instalacji ani konfiguracji na komputerze lokalnym.

Cloud Shell

W tym samouczku będziemy tworzyć i zarządzać różnymi zasobami i usługami w chmurze za pomocą wiersza poleceń w Cloud Shell.

Włącz interfejsy API

Oto interfejsy API, które musimy włączyć w projekcie:

  • Compute Engine API – tworzy i uruchamia maszyny wirtualne.
  • Interfejs API Kubernetes Engine – tworzy aplikacje oparte na kontenerach i nimi zarządza.
  • Cloud Build API – platforma Google Cloud do ciągłej integracji i ciągłego dostarczania.
  • Service Management API – umożliwia producentom usług publikowanie usług w Google Cloud Platform.
  • Cloud Resource Manager API – tworzy, odczytuje i aktualizuje metadane kontenerów zasobów Google Cloud.

Włącz wymagane interfejsy API za pomocą tego polecenia gcloud:

gcloud services enable compute.googleapis.com \
container.googleapis.com \
cloudbuild.googleapis.com \
servicemanagement.googleapis.com \
cloudresourcemanager.googleapis.com \
--project ${GOOGLE_CLOUD_PROJECT}

Tworzenie zasobnika GCS

Do przesłania testowych danych potrzebujemy zasobnika GCS. Aby zapewnić unikalność, utwórz zasobnik, używając w nazwie identyfikatora projektu:

gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket/ 

3. Tworzenie klastrów Kubernetes

Tworzenie klastra

Następnie utworzymy klaster GKE, który będzie hostować nasz system Jenkins, w tym pody, które będą wysyłane jako węzły robocze. Dodatkowy zakres wskazany przez flagę --scopes pozwoli Jenkinsowi uzyskać dostęp do repozytoriów Cloud Source Repositories i rejestru kontenerów. W Cloud Console wykonaj te czynności:

gcloud container clusters create jenkins-cd \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--scopes "https://www.googleapis.com/auth/source.read_write,cloud-platform" \
--cluster-version latest

Utworzymy też 2 klastry, które będą hostować wersje testowe i produkcyjne przykładowej aplikacji:

gcloud container clusters create staging \
--machine-type n1-standard-2 --num-nodes 1 \
--zone us-east1-d \
--cluster-version latest
gcloud container clusters create prod \
--machine-type n1-standard-2 --num-nodes 2 \
--zone us-east1-d \
--cluster-version latest

28b45298e1e82748.png Zweryfikuj

Po utworzeniu klastrów możemy potwierdzić, że działają one z użyciem gcloud container clusters list

Dane wyjściowe w kolumnie STATUS powinny zawierać RUNNING:

NAME        LOCATION    MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jenkins-cd  us-east1-d  1.15.9-gke.9    34.74.77.124  n1-standard-2  1.15.9-gke.9  2          RUNNING
prod        us-east1-d  1.15.9-gke.9    35.229.98.12  n1-standard-2  1.15.9-gke.9  2          RUNNING
staging     us-east1-d  1.15.9-gke.9    34.73.92.228  n1-standard-2  1.15.9-gke.9  2          RUNNING

4. Wdrażanie Jenkinsa za pomocą Helm

Instalowanie Helm

Do zainstalowania Jenkinsa w naszym klastrze użyjemy Helma, menedżera pakietów aplikacji dla Kubernetes. Aby rozpocząć, pobierz projekt zawierający pliki manifestu Kubernetes, których użyjemy do wdrożenia Jenkinsa:

git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git ~/continuous-deployment-on-kubernetes

Zmień bieżący katalog roboczy na katalog projektu:

cd ~/continuous-deployment-on-kubernetes/

Aby uzyskać uprawnienia roli administratora klastra, utwórz powiązanie roli klastra:

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)

Połącz się z klastrem Jenkinsa, uzyskując jego dane logowania:

gcloud container clusters get-credentials jenkins-cd --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Pobierz plik binarny Helm do konsoli Cloud:

wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz

Rozpakuj plik i skopiuj dołączony plik helm do bieżącego katalogu roboczego:

tar zxfv helm-v2.14.1-linux-amd64.tar.gz && \
cp linux-amd64/helm .

Tiller to serwerowa część Helma, która działa w klastrze Kubernetes. Utwórz konto usługi o nazwie tiller:

kubectl create serviceaccount tiller \
--namespace kube-system

Połącz go z rolą klastra cluster-admin, aby mógł wprowadzać zmiany:

kubectl create clusterrolebinding tiller-admin-binding \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller

Teraz możemy zainicjować Helm i zaktualizować repozytorium:

./helm init --service-account=tiller && \
./helm repo update

28b45298e1e82748.png Weryfikuj

Sprawdź, czy Helm jest gotowy do użycia, za pomocą polecenia ./helm version. Powinien on zwrócić numery wersji klienta i serwera:

Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}

Instalowanie Jenkinsa

Teraz, gdy Helm jest zainstalowany na naszym klastrze, możemy zainstalować Jenkinsa:

./helm install stable/jenkins -n cd \
-f jenkins/values.yaml \
--version 1.2.2 --wait

28b45298e1e82748.png Zweryfikuj

Sprawdźmy pody:

kubectl get pods

Wyjście powinno zawierać informację o naszym kontenerze Jenkinsa ze stanem RUNNING (działający):

NAME                          READY     STATUS    RESTARTS   AGE
cd-jenkins-7c786475dd-vbhg4   1/1       Running   0          1m

Sprawdź, czy usługa Jenkins została utworzona prawidłowo:

kubectl get svc

Dane wyjściowe powinny wyglądać mniej więcej tak:

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
cd-jenkins         ClusterIP   10.35.241.170   <none>        8080/TCP    2m27s
cd-jenkins-agent   ClusterIP   10.35.250.57    <none>        50000/TCP   2m27s
kubernetes         ClusterIP   10.35.240.1     <none>        443/TCP     75m

Instalacja Jenkinsa będzie używać wtyczki Kubernetes do tworzenia agentów kompilacji. W razie potrzeby będą one automatycznie uruchamiane przez głównego Jenkinsa. Po zakończeniu pracy są automatycznie zamykane, a ich zasoby są ponownie dodawane do puli zasobów klastra.

Łączenie z Jenkinsem

Jenkins działa w naszym klastrze, ale aby uzyskać dostęp do interfejsu użytkownika, skonfigurujmy przekierowanie portów w Cloud Shell:

export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &

Podczas instalacji zostało wygenerowane hasło administratora. Aby go pobrać:

printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

W górnej części Cloud Shell kliknij ikonę podglądu w przeglądarce 7ddf5a65fd556dd6.png i wybierz „Podejrzyj na porcie 8080”.

1d614c831a621cff.png

Powinien pojawić się ekran logowania do Jenkinsa, na którym możemy wpisać admin jako nazwę użytkownika i hasło zwrócone w poprzednim kroku:

9cba23e856cbc84f.png

Po kliknięciu Zaloguj się powinniśmy trafić na stronę główną Jenkinsa.

9261f3e914829137.png

5. Instalowanie i konfigurowanie wtyczki GKE

Wtyczka Google Kubernetes Engine umożliwia publikowanie wdrożeń utworzonych w Jenkinsie w klastrach Kubernetesa działających w GKE. W projekcie trzeba skonfigurować uprawnienia IAM. Skonfigurujemy ją za pomocą Terraform.

Najpierw pobierz projekt wtyczki GKE:

git clone https://github.com/jenkinsci/google-kubernetes-engine-plugin.git ~/google-kubernetes-engine-plugin

Automatyczna konfiguracja uprawnień IAM

Zmień bieżący katalog roboczy na katalog rbac projektu GKE, który wcześniej sklonowaliśmy:

cd ~/google-kubernetes-engine-plugin/docs/rbac/

gcp-sa-setup.tf to plik konfiguracji Terraform, który utworzy niestandardową rolę uprawnień GCP z ograniczonymi uprawnieniami oraz konto usługi GCP, któremu zostanie przypisana ta rola. Plik wymaga wartości zmiennych nazwy projektu, regionu i konta usługi. Te wartości podajemy, deklarując najpierw te zmienne środowiskowe:

export TF_VAR_project=${GOOGLE_CLOUD_PROJECT}
export TF_VAR_region=us-east1-d
export TF_VAR_sa_name=kaniko-role

Zainicjuj Terraform, wygeneruj plan i zastosuj go:

terraform init
terraform plan -out /tmp/tf.plan
terraform apply /tmp/tf.plan && rm /tmp/tf.plan

Aby zapisać pliki w zasobniku Cloud Storage, konto usługi musi mieć uprawnienia administratora pamięci masowej:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \
--role 'roles/storage.admin'

Potrzebuje też uprawnień do kontenera na potrzeby etapów wdrażania w naszym potoku:

gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} --member \
serviceAccount:kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com --role 'roles/container.developer'

Teraz możemy używać Helm do konfigurowania uprawnień klastra dla wtyczki GKE za pomocą narzędzia gke robot deployer. Zmień katalog roboczy na katalog helm projektu GKE:

cd ~/google-kubernetes-engine-plugin/docs/helm/

Zainstaluj za pomocą podanej karty Helm:

export TARGET_NAMESPACE=kube-system && \
envsubst < gke-robot-deployer/values.yaml | helm install ./gke-robot-deployer --name gke-robot-deployer -f -

6. Konfigurowanie Jenkinsa

Klucze kont usługi

Aby konto usługi działało prawidłowo, musimy wygenerować plik klucza prywatnego i dodać go jako obiekt tajny Kubernetes. Najpierw wygeneruj plik za pomocą tego polecenia gcloud:

gcloud iam service-accounts keys create /tmp/kaniko-secret.json --iam-account kaniko-role@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com

Utworzymy klucz obiektu tajnego w magazynie obiektów tajnych Kubernetes za pomocą tego pliku:

kubectl create secret generic jenkins-int-samples-kaniko-secret --from-file=/tmp/kaniko-secret.json 

Pobierz plik JSON na dysk lokalny, klikając opcję Pobierz plik w menu z 3 kropkami w Cloud Shell:

c40378e72013b843.png

Wpisz ścieżkę do pliku /tmp/kaniko-secret.json i kliknij Pobierz.

W panelu po lewej stronie na stronie Jenkinsa kliknij kolejno Dane logowania i System.

6c140f7e6bb82f8.png

3b874912cdc8019b.png

W sekcji strony zatytułowanej System kliknij Uprawnienia globalne,a następnie po lewej stronie kliknij Dodaj uprawnienia:

4350c0e68561119b.png

3d3526551cdae8b.png

W menu Typ wybierz Konto usługi Google z kluczem prywatnym. Wpisz „kaniko-role” jako nazwę, a następnie prześlij klucz JSON utworzony w poprzednich krokach i kliknij OK.

b0502213408e730e.png

Zmienne środowiskowe

Zanim utworzymy potok wielogałęziowy, musimy zdefiniować w Jenkinsie kilka zmiennych środowiskowych. Są to:

  • JENK_INT_IT_ZONE – strefa klastra Kubernetes. W naszym przypadku us-east1-d
  • JENK_INT_IT_PROJECT_ID – odnosi się do identyfikatora projektu GCP hostującego tę instancję Jenkinsa.
  • JENK_INT_IT_STAGING – nazwa klastra „statycznego” (na potrzeby demonstracji jest to staging).
  • JENK_INT_IT_PROD – nazwa klastra produkcyjnego. Na potrzeby demonstracji: prod
  • JENK_INT_IT_BUCKET – zasobnik Google Cloud Storage utworzony w poprzednim kroku
  • JENK_INT_IT_CRED_ID – odnosi się do danych logowania utworzonych za pomocą pliku JSON w poprzednim kroku. Wartość powinna być zgodna z nazwą, którą jej nadaliśmy, kaniko-role

Aby je dodać, wybierz Zarządzaj Jenkinsem:

d54f279190a07878.png

Następnie Skonfiguruj system:

ce79d218b2799640.png

Pojawi się sekcja o nazwie Właściwości globalne. Gdy zaznaczysz pole Zmienne środowiska, pojawi się przycisk Dodaj, który pozwoli Ci dodać zmienne powyżej jako pary klucz-wartość:

81aa222a2b17b2cc.png

Aby zastosować zmiany, kliknij przycisk Zapisz u dołu strony.

7. Konfigurowanie potoku

W Jenkinsie kliknij „Nowy element”:

8d1270ce4d7b6a8a.png

Wpisz „jenkins-integration-sample” jako nazwę, jako typ projektu wybierz „Multibranch Pipeline” i kliknij OK:

eb071ecfbb4d775b.png

Przekierujemy Cię na stronę konfiguracji potoku. W sekcji Źródła gałęzi wpisz https://github.com/GoogleCloudPlatform/jenkins-integration-samples.git jako Repozytorium projektu. W sekcji Konfiguracja kompilacji wpisz „gke/Jenkinsfile” jako ścieżkę skryptu.

5135bd6b0374508c.png

Aby zastosować te ustawienia, kliknij Zapisz. Po zapisaniu Jenkins rozpocznie skanowanie repozytorium i subsequentną kompilację każdej gałęzi. W miarę postępu tworzenia, uruchamiania i usuwania podów na stronie Zadania Kubernetes będą pojawiać się informacje o tych działaniach.

Po zakończeniu kompilacji na stronie Zadania Kubernetes znajdziesz 2 elementy o nazwie jenkins-integration-samples-gke, z których każdy odpowiada klastrowi produkcyjnemu lub testowemu. Stan: OK:

bdec6b1753d1ba07.png

Po wykonaniu tego polecenia gcloud zobaczysz, że obraz kontenera został przesłany do Google Container Registry zgodnie z naszym potokiem:

gcloud container images list

Aby wyświetlić zadanie w przeglądarce, uzyskaj poświadczenia do klastra produkcyjnego:

gcloud container clusters get-credentials prod --zone us-east1-d --project ${GOOGLE_CLOUD_PROJECT}

Aby skonfigurować przekierowanie portu z portu 8081 powłoki na port 8080 obciążenia, uruchom następujące polecenie:

export POD_NAME=$(kubectl get pods -o jsonpath="{.items[0].metadata.name}") &&
kubectl port-forward $POD_NAME 8081:8080 >> /dev/null &

U góry Cloud Shell kliknij ikonę podglądu w przeglądarce i wybierz „Podgląd na porcie 8081”.

1b19b5b56f1bae7.png

e80e995e71763bb2.png

8. Czyszczenie

Poznaliśmy sposób wdrażania Jenkinsa i przykładowego potoku wielogałęziowego w Kubernetes. Teraz czas wyczyścić projekt ze wszystkich utworzonych zasobów.

Usuwanie projektu

Jeśli wolisz, możesz usunąć cały projekt. W konsoli GCP otwórz stronę Menedżer zasobów w chmurze:

Na liście projektów wybierz projekt, nad którym pracujesz, i kliknij Usuń. Pojawi się prośba o wpisanie identyfikatora projektu. Wpisz hasło i kliknij Wyłącz.

Możesz też usunąć cały projekt bezpośrednio z Cloud Shell za pomocą gcloud:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Jeśli wolisz usuwać poszczególne elementy podlegające rozliczeniu pojedynczo, przejdź do następnej sekcji.

Klaster Kubernetes

Aby usunąć cały klaster Kubernetes za pomocą gcloud:

gcloud container clusters delete jenkins-cd --zone=us-east1-d

Zasobniki na dane

Usuń wszystkie przesłane pliki i usuń nasz bucket za pomocą gsutil:

gsutil rm -r gs://${GOOGLE_CLOUD_PROJECT}-jenkins-test-bucket

Obrazy w Google Container Registry

Usuniemy obrazy z Google Container Registry, korzystając z digestów obrazów. Najpierw pobierz zbiorcze podsumowania za pomocą tego polecenia:

gcloud container images list-tags gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke --format="value(digest)"

Następnie dla każdego zwróconego podsumowania:

gcloud container images delete gcr.io/${GOOGLE_CLOUD_PROJECT}/jenkins-integration-samples-gke@sha256:<DIGEST>

9. Gratulacje!

Super! Udało się. Znasz już metody wdrażania Jenkinsa w GKE i przydzielania zadań do klastrów Kubernetes.

Omówione zagadnienia

  • Wdrożyliśmy klaster Kubernetes i za pomocą Helma zainstalowaliśmy Jenkinsa.
  • Zainstalowaliśmy i skonfigurowaliśmy wtyczkę GKE, aby umożliwić Jenkinsowi wdrażanie artefaktów kompilacji w klastrach Kubernetes
  • Skonfigurowaliśmy Jenkinsa, aby ustawić potok wielogałęziowy, który wysyła pracę do klastrów GKE.