Я люблю Gitlab, правда, и когда я начал работать с Gitlab и GitlabCI в 2016 году, каждый проект, с которым мы должны его использовать, я боролся с некоторыми базовыми вещами. Это то, что мы собираемся охватить, такие как отсутствие плагинов и возможность повторного использования вашего CI YAML.
Итак, давайте поговорим о том, что мы собираемся делать. Поскольку Gitlab CI не имеет плагинов или даже завитков, писать YAML по нескольким причинам очень сложно: экранирование специальных символов, двойные и одинарные кавычки, конкатенация и т. Д.
Итак, в этой статье мы представим простую идею набора инструментов (я был вдохновлен DPL, и я также призываю вас сделать это). Это довольно простая идея, которая может помочь вам со сложными конвейерами и повторным использованием кода внутри конвейеров. Вместо того, чтобы писать все внутри вашего .gitlab-ci.yml, мы собираемся создать набор инструментов для выполнения действий.
Вам также могут понравиться:
Многоразовый код: Хороший, Плохой и Уродливый
Эта проблема
Если мы хотим создать релиз внутри нашего Gitlab, и мы используем Community Edition. Мы должны сделать что-то вроде этого:
YAML
xxxxxxxxxx
1
create_release
2
stage deploy
3
image docker latest
4
tags
5
docker_runner
6
script
7
curl --header 'Content-Type application/json' --header "PRIVATE-TOKEN: gDybLx3yrUK_HLp3qPjS" --data ' "name""New release" "tag_name""v0.3" "description""Super nice release" "milestones""v1.0" "v1.0-rc" "assets" "links" "name""hoge" "url""https://google.com" ' --request POST https://gitlab.example.com/api/v4/projects/24/releases
8
only
9
master
10
merge_request
Да, это не совсем верно? И угадайте, что? Это не сработает без каких-либо усилий, чтобы убежать и сделать кавычки правильными, это будет трудно исправить, и еще одна огромная проблема в том, что все ваши конвейеры должны будут скопировать и вставить этот ужасный YAML.
Создание решения
Так как же сделать это более понятным и легким для нас? Вам понадобится:
- Python 3.7
- докер
- Соответствующие библиотеки
Давайте начнем с основ, как нам создать новую версию с Python? Да, используя оболочку Python-Gitlab , так что давайте начнем!
Перед тем, как начать писать код, вы должны настроить свою среду и выполнить:
Оболочка
1
pip install python
Затем создает новый скрипт Python с именем create_release.py, который будет создавать объект Gitlab и затем поддерживать функцию для получения идентификатора проекта. Это будет полезно для создания нашего релиза.
питон
xxxxxxxxxx
1
import os
2
import gitlab
3
#Creates a Gitlab Connection object, you must create your token on Gitlab
5
gl = gitlab.Gitlab('https://gitlab.example.com/gitlab', private_token=os.environ['your_token'])
6
#Creates a function to get the project internal ID from the CI.
8
def get_project(project_id):
9
return gl.projects.get(project_id)
Теперь, когда у нас есть функция поддержки, давайте создадим функцию create release.
питон
xxxxxxxxxx
1
import os
2
import gitlab
3
#Creates a Gitlab Connection object
5
gl = gitlab.Gitlab('https://gitlab.example.com/gitlab', private_token=os.environ['your_token'])
6
#Creates a function to get the project internal ID from the CI.
8
def get_project(project_id):
9
return gl.projects.get(project_id)
10
11
#Creates the create_release function
12
def create_release(project_id, version):
13
#Gets the Project ID to be used later and stores to a variable.
14
project = get_project(project_id)
15
#defines the information to go to the release.
16
release_name = "My initial release"
17
description = "My awesome release notes"
18
#Creates the new release.
19
release = project.releases.create({'name': release_name, 'tag_name': version, 'description': description })
20
print(f'Created a new release with the tag: {tag_name} and project ID is: {project_id}')
21
#Creates the release!
22
create_release("24","v1.0")
Хорошо, у этого кода много проблем, таких как жестко закодированная информация, возможность повторного использования и т. Д. Но давайте посмотрим, как это будет выглядеть, если мы будем использовать его в нашем .gitlab-ci-yml:
YAML
xxxxxxxxxx
1
before_script
2
pip install python-gitlab
3
create_release
4
stage deploy
5
image docker latest
6
tags
7
docker_runner
8
script
9
python create_release.py
10
only
11
master
12
merge_request
Хорошо, это намного лучше, верно? Давайте сделаем это еще лучше на следующем шаге.
Нажмите!
Нажмите ! Click - это пакет, который позволяет вам создавать CLI из скриптов Python.
Реализация клика позволит нам очень просто использовать параметры / опции в нашем скрипте. Для этой функции мы будем получать идентификатор проекта непосредственно из предопределенной переменной Gitlab-CI и тега из git. В этой статье я не буду рассказывать о потоке CI или о том, как создать тег; Я просто предположу, что у вас есть свои способы создания и определения тегов.
Итак, начнем:
Это пример реализации Click:
питон
xxxxxxxxxx
1
import click
2
command() .
3
option('--count', default=1, help='Number of greetings.') .
4
option('--name', prompt='Your name', .
5
help='The person to greet.')
6
def hello(count, name):
7
"""Simple program that greets NAME for a total of COUNT times."""
8
for x in range(count):
9
click.echo('Hello %s!' % name)
10
if __name__ == '__main__':
11
hello()
Хорошо, так что давайте использовать этот пример, чтобы сделать нашу
create_release
функцию командой CLI:питон
x
1
#!/usr/bin/env python
2
import os
4
import gitlab
5
import click
6
#Creates a Gitlab Connection object
8
gl = gitlab.Gitlab('https://gitlab.example.com/gitlab', private_token=os.environ['your_token'])
9
#Creates a function to get the project internal ID from the CI.
11
def get_project(project_id):
12
return gl.projects.get(project_id)
13
14
#Creates the create_release function and decorate with Click.
15
command() .
16
argument('project_id') .
17
argument('version') .
18
def create_release(project_id, version):
19
#Gets the Project ID to be used later and stores to a variable.
20
project = get_project(project_id)
21
22
#defines the information to go to the release.
23
release_name = "My initial release"
24
description = "My awesome release notes"
25
26
#Creates the new release.
27
release = project.releases.create({'name': release_name, 'tag_name': version, 'description': description })
28
print(f'Created a new release with the tag: {tag_name} and project ID is: {project_id}')
29
30
if __name__ == '__main__':
31
create_release()
Это должно сделать свое дело. Единственное отличие от примера в том, что мы используем аргументы вместо опций. Аргументы обязательны .
Хорошо, теперь наш CLI реализован, но как он выглядит на нашем .gitlab-ci.yml?
YAML
xxxxxxxxxx
1
before_script
2
pip install python-gitlab click
3
create_release
4
stage deploy
5
image docker latest
6
tags
7
docker_runner
8
script
9
./create_release.py $ CI_PROJECT_ID v1.0
10
only
11
master
12
merge_request
Хорошо, это намного лучше. Теперь у нас есть скрипт Python для командной строки, и мы используем предопределенные переменные для создания нашей версии!
Но подождите: мы собираемся использовать это снова и сейчас, этот скрипт на Python должен быть во всех наших репозиториях.
Есть последний улов!
Создание панели инструментов!
Помните, что одним из условий для этого был Докер ? Да, верно: мы собираемся создать нашего бегуна, который будет служить инструментарием DevOps. В нем будут все наши скрипты в / bin /, поэтому мы можем просто вызывать их!
Таким образом, вам понадобится новый файл Docker, который будет выполнять роль бегуна; Я использую официальный образ Python .
Я бы посоветовал вам создать новый репозиторий с вашим бегуном и скриптами Python; структура будет примерно такой:
Да, у вас должен быть CI для вашего образа бегуна.
Теперь для Dockerfile сделайте это просто:
Dockerfile
x
1
FROM python:latest
2
COPY scripts/ /usr/local/bin/
3
RUN apt update -y
Создайте образ, переместите его в предпочитаемый вами реестр, и теперь вы можете просто сделать это в своем исходном .gitlab-ci.yml:
YAML
x
1
before_script
2
pip install python-gitlab click
3
create_release
4
stage deploy
5
image devops_toolbox latest
6
tags
7
docker_runner
8
script
9
create-release $ CI_PROJECT_ID v1.0
10
only
11
master
12
merge_request
Итак, что изменилось?
- Мы переместили скрипт
create_release
P ython в наш репозиторий инструментов DevOps и удалили его из проекта, над которым мы работали. - Теперь мы назначаем этот конкретный этап для запуска внутри нашего образа «devops_toolbox», который содержит наш скрипт «create_release» Python. Когда вы сделаете это, мы можем вызвать его напрямую, потому что он находится на пути.
- Сценарий с нашим Python «create_release» без «расширения».
Это намного лучше, и его можно будет повторно использовать из вашего контейнера, так что на каждом этапе вам нужно будет выполнить его, используя тег вашего собственного бегуна.
Это всего лишь идея, вы можете создать несколько двоичных файлов для выполнения нескольких действий, слабых хуков, загружать артефакты в Nexus / Artifactory, развертывать двоичные файлы в своих службах, DPL и т. Д., Затем у вас будет полностью подключаемое изображение панели инструментов DevOps для поддержки вашего Continuous Интеграция и доставка.
Резюме
- Вместо дублирующих скриптов внутри вашего .gitlab-ci.yml, мы создали скрипт Python внутри нашего репо.
- Чтобы сделать его более читабельным, мы изменили скрипт Python с помощью Click !, превратив его в CLI.
- Чтобы сделать его еще лучше и использовать его повторно, мы встроили его в собственный образ Docker, который будет служить нам в качестве сценического бегуна в Gitlab-CI.
Вещи, которые я не охватил, которые вы должны изучить:
- Тесты Python
- Error treatment; remember if your API returns 404, the script may return exit code 0, and you must treat that.
- The entire CI/CD flow
That's it for now, hope it helps anyone using Gitlab CI.
Further Reading
In Defense of YAML