Przyjrzyjmy się kompilowaniu projektu w GO i temu, jak to działa w Gitlab CI.
Kompilacja
Aby zbudować, musimy wywołać go build -o binary_name
.
Jeśli projekt ma importy z repozytoriów innych firm, istnieją zależności zewnętrzne. Kompilacja dla języka GO będzie wymagała całego kodu źródłowego, w tym kodu biblioteki zależności. W związku z tym należy upewnić się, że biblioteki innych firm, które mogą nie być przechowywane w repozytorium, są również dostępne do kompilacji.
Producent lub plik do pobrania
W tej chwili aktualna wersja to 1.14.2. Począwszy od wersji GO 1.11 dostępna
jest funkcjonalność modułu (go modules
).Moduły GO działają w taki sposób, że GO samo ładuje wszystkie biblioteki innych firm po go run
wywołaniu lub go build
gdy wszystkie biblioteki są jawnie załadowane - . go get ./...
Kod źródłowy pobranych bibliotek jest zapisywany w $GOPATH/pkg/mod
lub do$HOME/go/pkg/mod
, jeśli zmienna środowiskowa $GOPATH
nie jest ustawiona.
Istnieje podejście do radzenia sobie z zależnościami zwane dostarczaniem. Moduły GO obsługują vendoring, więc jeśli określisz -mod=vendor_dir
, zależności zostaną pobrane do folderuvendor_dir
. Ten folder może znajdować się w repozytorium i zostać wypchnięty do repozytorium Git wraz z kodem źródłowym.
W przypadku korzystania z vendoringu zależności zostaną pobrane raz i dostarczone wraz z kodem źródłowym projektu, co pozwoli na szybsze kompilacje.
Gitlab
Gitlab zapewnia możliwość wykonywania różnych zadań po wypchnięciu do repozytorium.
Aby skorzystać z tej funkcji, należy dodać .gitlab-ci.yml
plik .
Kompilacja w Gitlabie
Musisz zdefiniować etapy i konkretne akcje, które mają być wykonywane w tych krokach. Dla każdej akcji można określić obraz platformy Docker.
Kod projektu zostanie automatycznie pobrany do folderu/builds/{project_group}/{project_name}
. Oznacza to, że nie ma potrzeby pobierania go ręcznie.
W poniższym kodzie zdefiniowałem krok kompilacji i tytułową akcję w nim:
stages:
— build
build:
image: rhaps1071/golang-1.14-alpine-git
stage: build
script:
— go get ./...
— GOARCH=amd64 GOOS=linux go build -ldflags "-extldflags '-static'" -o $CI_PROJECT_DIR/binary
artifacts:
paths:
— binary
Używany jest tutaj obraz dockera mojego autorstwa rhaps1071/golang-1.14-alpine-git.
Dodaje polecenie git
do . golang:1.14-alpine
Ta modyfikacja jest niezbędna dla polecenia go get ./...
, które ładuje zależności i używa git clone
.
Obraz podstawowy jest oparty na systemie Alpine Linux, ponieważ ta dystrybucja waży tylko kilka megabajtów.
Jednak rozmiar golang:1.14-alpine
waży 370 MB, co jest dużo, ale nadal jest dwukrotnym wzrostem w porównaniu z golang:1.14
(809 MB) opartym na Ubuntu.
Nie używam vendoringu, więc muszę pobrać zależności, aby skompilować. Aby to zrobić, wywołaj poleceniego get ./...
.
Jak powiedziałem powyżej, kod w Gitlab CI znajduje się w katalogu , który znajduje się poza $GOPATH
domeną /builds/{project_name}/{project_folder}
.
Aby to zadziałało, musi istnieć plik . go.mod
Możesz go utworzyć za pomocą go mod init
. Jeśli nie masz pliku go.mod
, zespół go get ./...
nie będzie w stanie określić zależności.
Jeśli Twój projekt nie korzysta z modułów GO, musisz przenieść kod źródłowy do pliku $GOPATH
.
W Gitlab CI ta kopia będzie wyglądać tak:- cp /builds/* $GOPATH/src/
Instrukcja artifacts pozwala na zapisanie dowolnego z plików lub folderów .gitlab-ci.yml
do pobrania, a także do wykorzystania w kolejnych etapach Gitlab CI.
Wdrożenie SSH
Przyjrzyjmy się wdrożeniu wynikowego pliku binarnego przy użyciu SSH.
deploy_stage:
image: kroniak/ssh-client
stage: deploy
environment:
name: stage
url: http://stage.project.com
when: manual
script:
— mkdir -p ~/.ssh
— echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
— chmod -R 700 ~/.ssh
— echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
— chmod 644 ~/.ssh/known_hosts
— echo "$CONFIG" > ./config.json
— scp -P$SSH_PORT -r ./config.json $SSH_USER@$SSH_HOST:/var/www/project/config/
— scp -P$SSH_PORT -r ./binary $SSH_USER@$SSH_HOST:~/binary_tmp
— ssh -p$SSH_PORT $SSH_USER@$SSH_HOST 'sudo service project stop && cp ~/binary_tmp /var/www/project/binary && sudo service project restart'
Również w tym przypadku używany jest dostosowany obraz Alpine Linux — rozmiar 12,1 MBkroniak/ssh-client
. Tym razem dodatkowo preinstalowany z klientem ssh, dzięki czemu ssh
scp
komendy i .Logika wdrażania jest następująca:
- Włączone są następujące zmienne Gitlab:
$SSH_PRIVATE_KEY
- klucz prywatny umożliwiający dostęp do serwera;$SSH_USER
,$SSH_HOST
,$SSH_PORT
to login i adres serwera do wdrożenia;$SSH_KNOWN_HOSTS
- Wpis dla pliku .ssh/known_hosts, za pomocą którego serwer jest weryfikowany.$CONFIG
– zawartość pliku konfiguracyjnego naszego serwisu w formacie json; - Podczas wdrażania najpierw wypełnij wszystkie niezbędne pliki danymi ze zmiennych Gitlab;
- Wszystkie niezbędne pliki są kopiowane na serwer za pomocą
scp
programu . Może być używanyrsync
, ponieważ kopiuje tylko pliki, które zostały zmienione i kopiuje je w postaci zarchiwizowanej. Jednak jeśli chodzi o 1-2 pliki, prawie nie ma wygranej. - Ostatnim krokiem jest zastąpienie pliku binarnego i ponowne uruchomienie naszej usługi;
Wynikowy plik .gitlab-ci.yml
w całości wygląda następująco:
stages:
— build
— deploy
build:
image: rhaps1071/golang-1.14-alpine-git
stage: build
script:
— go get ./...
— GOARCH=amd64 GOOS=linux go build -ldflags "-extldflags '-static'" -o $CI_PROJECT_DIR/binary
artifacts:
paths:
— binary
deploy_stage:
image: kroniak/ssh-client
stage: deploy
environment:
name: stage
url: http://stage.project.com
when: manual
script:
— mkdir -p ~/.ssh
— echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
— chmod -R 700 ~/.ssh
— echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
— chmod 644 ~/.ssh/known_hosts
— echo "$CONFIG" > ./config.json
— scp -P$SSH_PORT -r ./config.json $SSH_USER@$SSH_HOST:/var/www/project/config/
— scp -P$SSH_PORT -r ./binary $SSH_USER@$SSH_HOST:~/binary_tmp
— ssh -p$SSH_PORT $SSH_USER@$SSH_HOST 'sudo service project stop && cp ~/binary_tmp /var/www/project/binary && sudo service project restart'