08.05.2020 gitlab компиляция деплой ssh модули вендоринг ci-cd
Рассмотрим компиляцию проекта на GO в принципе и как это работает в Gitlab CI.
Для сборки нам необходимо вызвать go build -o binary_name
.
Если в вашем проекте есть импорты из сторонних репозиториев, значит есть внешние зависимости. Для компиляции для GO потребует весь исходный код, включая код библиотек-зависимостей. Таким образом для компиляции необходимо обеспечить доступность в том числе сторонних библиотек, которые могут не хранится в вашем репозитории.
На данный момент актуальной версией является 1.14.2.
Начиная с версии GO 1.11 доступна функциональностей модулей (go modules
).
Модули GO работают так, что сам GO подгружает все сторонние библиотеки
при вызове go run
, go build
или при явном подгрузке всех библиотек -
go get ./...
.
$GOPATH/pkg/mod
или в $HOME/go/pkg/mod
, если переменная окружения $GOPATH
не установлена.
Существует подход для работы с зависимостями, называемый вендоринг.
Модули GO поддерживают вендоринг так,
что если указать параметр -mod=vendor_dir
,
то зависимости будут скачаны в папку vendor_dir
.
Данная папка может находится внутри вашего репозитория и быть
запушена в Git репозиторий вместе с вашим исходным кодом.
При использовании вендоринга, зависимости будут скачаны единожды и будут поставляться вместе с исходным кодом проекта, что позволит быстрее выполнять сборку.
Gitlab предоставляет возможность выполнять различные задачи после пуша в репозиторий.
Чтобы задействовать эту функциональность,
необходимо добавить в корень репозитория файл .gitlab-ci.yml
.
Необходимо определить этапы (stages) и конкретные действия, выполняемые на этих этапах. Для каждого действия можно задать докер-образ.
Код вашего проекта будет автоматически скачан в папку /builds/{project_group}/{project_name}
.
Это означает, что нет никакой необходимости скачивать его вручную.
В коде ниже я задал этап build и одноименное действие в нем:
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
Здесь используется докер-образ моего авторства
rhaps1071/golang-1.14-alpine-git.
Он добавляет команду git
в golang:1.14-alpine
.
Данная доработка необходима для команды go get ./...
,
которая подгружает зависимости и использует git clone
.
Базовый образ основан на Alpine Linux, так как данный дистрибутив
весит всего несколько мегабайт.
Однако размер golang:1.14-alpine
весит 370MB, что много,
но все же двухкратный выйгрыш по сравнению с golang:1.14
(809MB),
основанным на Ubuntu.
Я не использую вендоринг, поэтому для сборки мне необходимо скачать зависимости.
Для этого вызывается команда go get ./...
.
Как я сказал выше, код в Gitlab CI расположен в папке /builds/{project_name}/{project_folder}
,
которая находится вне $GOPATH
.
Для того, чтобы это работало, в корне вашего проекта должен быть файл go.mod
.
Создать его можно с помощью команды go mod init
.
При отсутствии файла go.mod
команда go get ./...
не сможет выяснить зависимости.
Если ваш проект не использует модули GO,
то ваш исходный код перед выполнением каких-либо команд нужно будет перенести в $GOPATH
.
В Gitlab CI это копирование будет выглядеть так:
- cp /builds/* $GOPATH/src/
Инструкция artifacts в .gitlab-ci.yml
позволяет сохранить какой-либо из файлов или папок
для скачивания, а также для использования на следующих этапах Gitlab CI.
Рассмотрим деплой полученного бинарника с помощью 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'
Здесь снова использован кастомизированный образ Alpine Linux — kroniak/ssh-client
размером 12.1MB.
На этот раз в нем дополнительно предустановлен ssh-клиент,
благодаря чему осуществляется вызов команд ssh
и scp
.
Логика деплоя выглядит следующим образом:
$SSH_PRIVATE_KEY
-
приватный ключ для доступа к серверу;$SSH_USER
, $SSH_HOST
, $SSH_PORT
—
логин, и адрес сервера для деплоя;$SSH_KNOWN_HOSTS
— запись для файла .ssh/known_hosts,
через который происходит валидация сервера;$CONFIG
— содержимое файла конфигурации нашего сервиса в формате json;scp
.
Можно было бы использовать rsync
, так как он
копирует только изменившиеся файлы и копирует их в архивированном виде.
Однако когда речь об 1-2 файлах, то выйгрыша практически нет.Полученный файл .gitlab-ci.yml
полностью выглядит следующим образом:
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'