Исходные данные: операционная система Debian bookworm11.
Для отчета по курсу требуется реализовать индивидуальное задание включающее разработку "драйвера" файловой системы, а также произвести настройку инфраструктуры для разработки включающей CI/CD и автотестирование. К отчету прикладывается: исходный код "драйвера", декларативное описание конфигурации инфраструктуры в ansible, список коммитов с датами в gitlab по "драйверу" и инфраструктуре.
Лекция 1. GitLab
1. Установить пакеты curl и sudo
2. Добавить репозитарий gitlab-ce через скрипт:
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
3. Установить пакет gitlab-ce.
4. Внести правки в /etc/gitlab/gitlab.rb в соответствии с примером конфигурации /etc/gitlab/gitlab.rb:
external_url 'http://gitlab.develop.local' web_server['external_users'] = ['www-data'] nginx['enable'] = false
5. Установить пакет веб-сервера nginx.
6. Настроить виртуальный сайт gitlab.develop.local в соответствии с примером конфигурации /etc/nginx/sites-available/gitlab:
upstream gitlab-workhorse { server unix://var/opt/gitlab/gitlab-workhorse/sockets/socket fail_timeout=0; } server { server_name gitlab.develop.local; server_tokens off; root /opt/gitlab/embedded/service/gitlab-rails/public; client_max_body_size 250m; access_log /var/log/nginx/gitlab_access.log; error_log /var/log/nginx/gitlab_error.log; location / { proxy_read_timeout 3600; proxy_connect_timeout 300; proxy_redirect off; proxy_buffering off; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_pass http://gitlab-workhorse; } error_page 502 /502.html; }
6. Выполнить начальную конфигурацию gitlab сервера:
gitlab-ctl reconfigure
7. Внести в файл /etc/hosts на виртуальной машине запись:
127.0.0.1 gitlab.develop.local
8. Внести в файл hosts на локальной машине, для операционной системы windows путь c:\windows\system32\drivers\etc\hosts в соответствии с примером конфигурации:
192.168.0.40 gitlab.develop.local
9. Произвести начальную настройку gitlab через браузер по адресу http://gitlab.develop.local
10. Создать дополнительного пользователя user и группу fstask по адресам:
http://gitlab.develop.local/admin/users/new
http://gitlab.develop.local/admin/groups/new
11. Добавить пользователя как Maintainer группы fstab
12. Зайти под пользователем user, создать проект с файлом README.md и названием test в группе fstask:
http://gitlab.develop.local/fstask/test
Лекция 2. Docker и GitLab-CI
1. Ознакомиться с инструкцией по установке gitlab-runner по адресу:
https://docs.gitlab.com/runner/install/linux-repository.html
2. Добавить apt репозитарии gitlab-runner через скрипт:
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
3. Установить пакет gitlab-runner
4. Добавить apt репозитарии для установки docker в файл /etc/apt/sources.list.d/docker.list:
deb https://download.docker.com/linux/debian bookworm stable
5. Добавить сигнатуры от репозитория docker:
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
6. Обновить дерево пакетов в системе:
apt update
7. Установить пакет docker-ce:
apt install docker-ce docker-ce-cli containerd.io
8. Зарегистрировать gitlab-runner. Предварительно нужно зайти под аккаунтом администратора по адресу http://gitlab.develop.local/admin/runners и узнать значение токена для регистрации, так же необходимо указать название тега и типа раннера docker. Интерактивная команда запуска регистрации:
gitlab-runner register
9. Добавить пользователя gitlab-runner в группу docker:
gpasswd -a gitlab-runner docker
10. Удалить файл приводящий к проблемам при shell runner-ах:
rm /home/gitlab-runner/.bash_logout
11. Создать в проекте http://gitlab.develop.local/fstask файл .gitlab-ci.yml со следующим содержимым:
stages: - test mytest: image: docker:stable stage: test tags: - docker script: - docker build -t test . - docker run test
12. Создать в проекте http://gitlab.develop.local/fstask файл Dockerfile:
FROM alpine:latest RUN mkdir /app COPY app.sh /app RUN chmod +x /app/app.sh CMD /app/app.sh
13. Создать в проекте http://gitlab.develop.local/fstask файл app.sh:
#!/bin/sh echo Our first program exit 0
14. Модифицировать файл /etc/gitlab-runner/config.toml в соответствии с примером конфигурации:
[runners.docker] tls_verify = false image = "alpine:latest" privileged = false disable_entrypoint_overwrite = false oom_kill_disable = false disable_cache = false volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"] shm_size = 0 extra_hosts = ["gitlab.develop.local:192.168.0.40"] #your IP
15. Перезапустить сервис gitlab-runner:
systemctl restart gitlab-runner.service
16. После всех этапов необходимо перевыполнить последний pipeline по адресу http://gitlab.develop.local/fstask/test/pipelines, он должен иметь статус passed.
Лекция 3. Nexus Repository
Особенность заключается в том что в Debian Bookworm официально отсутствует java JRE/JDK 8-й версии, требуемый для корректного функционирования nexus.
Существует 2 варианта как можно это исправить:
Первый способ (более простой)
Установить пакет nvidia-openjdk-8-jre: apt install nvidia-openjdk-8-jre
Установить пакет ca-certificates-java: apt install ca-certificates-java
Тогда корневой директорией с Java 8 будет /usr/lib/jvm/nvidia-java-8-openjdk-amd64
Второй способ
Добавить репозиторий от версии Stretch (oldstable).
1. Добавить в файл /etc/apt/apt.conf.d/99release запись:
APT::Default-Release "stable";
2. Добавить в /etc/apt/sources.list строку:
deb http://security.debian.org/debian-security stretch/updates main
3. Обновить репозитарий пакетов.:
apt update
4. Установить пакет с java 8-й версии:
apt install openjdk-8-jre
Установка Nexus:
1. Скачать архив с дистрибутивом Nexus:
wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz
2. Переместить и разархивировать пакет:
mv latest-unix.tar.gz /opt && cd /opt && tar xf latest-unix.tar.gz
3. Создать символическую ссылку с общем именем для упращения обновления:
ln -s nexus-3.42.0-01 nexus
4. Изменить файл nexus.vmoptions в каталоге nexus/bin, чтобы уменьшить требования к занимаемой оперативной памяти:
-Xms768m -Xmx768m -XX:MaxDirectMemorySize=768m
5. Создать Unit-файл /etc/systemd/system/nexus.service для автоматического запуска службы через systemd:
[Unit] Description=nexus service After=network.target [Service] Type=forking LimitNOFILE=65536 ExecStart=/opt/nexus/bin/nexus start ExecStop=/opt/nexus/bin/nexus stop User=nexus Restart=on-abort [Install] WantedBy=multi-user.target
6. Запустить Nexus первый раз в ручном режиме:
/opt/nexus/bin/nexus run
7. Обновить информацию о сервисах и включить nexus:
systemctl daemon-reload
systemctl enable nexus.service
8. Создать пользователя nexus с отключенным входом в систему:
useradd nexus -s /bin/false
9. Изменить права доступа на каталоги nexus sonatype-work nexus-3.42.0-01 в /opt:
chown -R nexus:nexus nexus sonatype-work nexus-3.42.0-01
10. Запустить службу nexus:
systemctl start nexus.service
11. Добавить виртуальный сайт в список nginx /etc/nginx/sites-available/nexus со следующим содержимым:
server { server_name nexus.develop.local; proxy_send_timeout 120; proxy_read_timeout 300; proxy_buffering off; keepalive_timeout 5 5; tcp_nodelay on; client_max_body_size 1G; location / { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
12. Включить виртуальный сайт nexus:
cd /etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/nexus nexus
systemctl reload nginx
13. Добавить в файл /etc/hosts на сервере запись:
127.0.0.1 nexus.develop.local
14. Внести в файл hosts на локальной машине, для операционной системы windows путь c:\windows\system32\drivers\etc\hosts в соответствии с примером конфигурации:
192.168.0.40 nexus.develop.local
15. Зайти по адресу http://nexus.develop.local и авторизоваться пользователем admin с паролем из файла /opt/sonatype-work/nexus3/admin.password
16. Создать новый репозиторий с именем main и портом 18888 по адресу http://nexus.develop.local/#admin/repository/repositories:
17. Добавить новую роль main-access с привилегиями nx-repository-view-docker-main-* и пользователя user с паролем 12345678 привязанного к роли main-access.
18. Для проверки подключения к репозиторию, предварительно, необходимо создать файл /etc/docker/daemon.json, с опцией разрешающей доступ к репозиторию по протоколу HTTP:
{ "insecure-registries" : ["http://nexus.develop.local:18888"] }
19. Перечитать конфигурационный файл службой docker'a:
systemctl reload docker
20. Проверить корректность авторизации пользователя в удаленном репозитории:
docker login -u user -p 12345678 nexus.develop.local:18888
rm /root/.docker/config.json
21. Модифицировать конфигурационный файл /etc/gitlab-runner/config.toml добавив информацию о новом псевдониме:
extra_hosts = ["gitlab.develop.local:192.168.0.40", "nexus.develop.local:192.168.0.40"]
22. Перезапустить gitlab-runner:
systemctl restart gitlab-runner
23. Добавить переменные USER_LOGIN и USER_PASS в настройки проекта fstask/test (пример адреса http://gitlab.develop.local/fstask/test/-/settings/ci_cd)
24. Изменить gitlab-ci файл на следующее содержание:
stages: - build - test variables: NEXUS_HOST: nexus.develop.local:18888 IMAGE_NAME: $NEXUS_HOST/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST mybuild: image: docker:stable stage: build tags: - docker script: - docker build --pull -t $IMAGE_NAME . - docker push $IMAGE_NAME mytest: image: docker:stable stage: test tags: - docker script: - docker pull $IMAGE_NAME - docker run $IMAGE_NAME
25. Проверить, что pipeline состоит из двух этапов и оба этапа завершены со статусом passed.
Лекция 4. Сборка основного проекта
1. Изменить роль пользователя user http://gitlab.develop.local/groups/fstask/-/group_members на Owner
2. Перенести CI/CD переменные USER_LOGIN и USER_PASS из проекта test в http://gitlab.develop.local/fstask
3. Создать базовый проект http://gitlab.develop.local/fstask/gcc-base
4. Создать Dockerfile включающий компилятор и систему сборки:
FROM alpine:latest RUN apk update && apk add \ --virtual mybuild \ build-base \ cmake
5. Создать .gitlab-ci.yml описывающий этапы сборки и тегирования:
stages: - build - release variables: NEXUS_HOST: nexus.develop.local:18888 IMAGE_NAME: $NEXUS_HOST/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG IMAGE_RELEASE_NAME: $NEXUS_HOST/$CI_PROJECT_NAME:latest buildgcc: image: docker:stable stage: build tags: - docker before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST script: - docker build --pull -t $IMAGE_NAME . - docker push $IMAGE_NAME release: image: docker:stable stage: release tags: - docker before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST script: - docker pull $IMAGE_NAME - docker tag $IMAGE_NAME $IMAGE_RELEASE_NAME - docker push $IMAGE_RELEASE_NAME
6. Проверить, что pipeline проекта gcc-base состоит из двух этапов и оба этапа завершены со статусом passed.
7. Создать основной проект http://gitlab.develop.local/fstask/fatdriver
8. Добавить исходный код программы в main.cpp:
#include < iostream>using namespace std; int main() { cout << "Hello WOrld" << endl; return 0; }
9. Написать файл сборки для cmake - CMakeLists.txt, включающий запуск тестов:
cmake_minimum_required(VERSION 2.8) add_executable(main main.cpp) enable_testing() add_test(NAME Test1 COMMAND "./main")
10. Создать Dockerfile основанный на образе gcc-base и добавить команды для сборки приложения и запуска тестов в контейнере:
FROM nexus.develop.local:18888/gcc-base:latest RUN mkdir /app COPY main.cpp CMakeLists.txt /app/ CMD cd /app && cmake . && make && make test
11. Добавить .gitlab-ci.yml в основной проект, включающий этап сборки и тестирования:
stages:
stages: - build - test variables: NEXUS_HOST: nexus.develop.local:18888 IMAGE_NAME: $NEXUS_HOST/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST mybuild: image: docker:stable stage: build tags: - docker before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST script: - docker build --pull -t $IMAGE_NAME . - docker push $IMAGE_NAME mytest: image: docker:stable stage: test tags: - docker script: - docker pull $IMAGE_NAME - docker run $IMAGE_NAME
12. Проверить, что pipeline проекта fatdriver состоит из двух этапов и оба этапа завершены со статусом passed.
Лекция 5. Gitlab артифакты и ansible
Добавление триггера для пересборки fatdriver по сигналу от gcc-base:
1. Добавим запуск через trigger_job в .gitlab-ci.yml проекта gcc-base :
trigger_job: stage: child trigger: project: fstask/fatdriver
2. Изменим запуск тестов с make test на ctest, чтобы можно было сохранить протокол запуска в Dockerfile проекта fstask, полученный файл:
FROM nexus.develop.local:18888/gcc-base:latest RUN mkdir /app COPY main.cpp CMakeLists.txt /app/ CMD cd /app && cmake . && make && ctest -O log.txt .
3. Добавим в gitlab-ci файл указание на сохранение артифакта log.txt с временем хранения 1 неделя.
4. Добавим копирование файла log.txt в запущенный контейнер верхнего уровня, в результате получится следующий gitlab-ci файл:
stages: - build - test variables: NEXUS_HOST: nexus.develop.local:18888 IMAGE_NAME: $NEXUS_HOST/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG TEST_CONTAINER_NAME: testimage mybuild: image: docker:stable stage: build tags: - docker before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST script: - docker build --pull -t $IMAGE_NAME . - docker push $IMAGE_NAME mytest: image: docker:stable stage: test tags: - docker before_script: - docker login -u $USER_LOGIN -p $USER_PASS $NEXUS_HOST script: - docker pull $IMAGE_NAME - docker rm -v $TEST_CONTAINER_NAME || echo - docker run --name $TEST_CONTAINER_NAME $IMAGE_NAME - docker cp $TEST_CONTAINER_NAME:/app/log.txt . artifacts: paths: - ./log.txt expire_in: 1 week
Подготовка системы автоматизации и декларативного описания администрирования - Ansible.
1. Установим менеджер пакетов python pip3:
apt install python3-pip
2. Установим пакет ansible (если возникает проблема, то добавьте параметр break-system-packages):
pip3 install --break-system-packages ansible
3. Для подключения к удаленному узлу создадим пару ключей ssh:
ssh-keygen
4. Добавим публичный ключ для удаленного подключения:
cat /home/user/.ssh/id_rsa.pub >> .ssh/authorized_keys
5. Создадим простой playbook для установки nginx, со следующей структурой: playbook/{roles, handlers, templates}, сам playbook nginx.yml разместим в каталоге playbook.
6. Добавим пользователя user в /etc/sudoers файл, для этого добавим строку:
user ALL=(ALL:ALL) ALL
7. Создадим inventory файл hosts.txt, где адрес 192.168.0.40 - IP адрес вашего хоста:
[test] 192.168.0.40
8. Создадим playbook/nginx.yml, добавим опцию become: true, для того чтобы поднять права пользователя до root через sudo:
- hosts: test become: true roles: - nginx
9. Добавим задачу в роли nginx playbook/nginx/tasks/main.yml, следующего содержания:
- name: Install nginx apt: name: nginx state: present update_cache: true
10. Первый раз запустим playbook без параметра -C, чтобы автоматически установился python-apt, на запрос пароля введем пароль пользователя(!) :
ansible-playbook -i hosts.txt playbook/nginx.yml -K -D
11. Добавим перезапуск сервиса nginx через handler, создав файл playbook/nginx/handlers/main.yml:
- name: reload nginx service: name: nginx state: reloaded
12. Скопируем старый файл конфигурации в шаблоны и внесем несколько корректировок:
cp /etc/nginx/nginx.conf playbook/roles/nginx/templates/nginx.conf.j2
13. Изменим файл playbook/nginx/tasks/main.yml роли следующим образом (добавим удаление сайта по умолчанию и создание конфига из шаблона):
- name: Install nginx apt: name: nginx state: present update_cache: true - name: Remove default site file: path: /etc/nginx/sites-enabled/default state: absent notify: - reload nginx - name: Create nginx.conf template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf mode: 0644 owner: root group: root notify: - reload nginx
14. Проверим изменения с параметром -C :
ansible-playbook -i hosts.txt playbook/nginx.yml -K -D -C
15. Применим изменения на сервере без -C :
ansible-playbook -i hosts.txt playbook/nginx.yml -K -D
16. Повторный перезапуск playbook'а должен показать, что изменения на сервере больше не вносились.
Лекция 6. Установка и обновление nexus через ansible
1. Создадим новый проект infrastructure в gitlab: http://gitlab.develop.local/projects/new
2. Добавим публичный ключ для авторизации gitlab от пользователя, по адресу http://gitlab.develop.local/profile/keys
3. Перейдем в каталог с playbook'ами с прошлой лекции и добавим ее в gitlab:
git init
git remote add origin git@gitlab.develop.local:user/infrastructure.git
git add .
git commit -m "Initial commit"
git push -u origin master
4. Разобъем структуру playbook'a по установке на 4 этапа: Подготовка, Установка или Обновление, Обновление прокси и Пост обработка.
5. Модифицируем файл hosts.txt из ~/testbook, где 192.168.0.40 ваш IP-адрес:
[nginx] 192.168.0.40 [nexus] 192.168.0.40
6. Создадим роль playbook/roles/nexus со следующей структурой: defaults, handlers, tasks, templates
7. Создадим файл с начальными установками defaults/main.yml:
nexus_install_dir: "/opt" nexus_user: "nexus" nexus_group: "{{ nexus_user }}" nexus_upgrade: false nexus_min_heap: "1200m" nexus_max_heap: "{{ nexus_min_heap }}" nexus_direct_memory: "{{ nexus_min_heap }}" nexus_version_running: ""
8. Создадим обработчики handlers/main.yml, которые потребуются в ходе исполнения задач:
- name: nexus stop systemd: name: nexus.service state: stopped - name: nexus start systemd: name: nexus.service state: started - name: nexus restart systemd: name: nexus.service state: restarted - name: nexus unit reload systemd: daemon-reload: yes name: nexus.service - name: nexus wait port wait_for: port: 8081 timeout: 600
9. Скопируем шаблоны для юнита systemd и nginx из лекции 3:
cp /etc/systemd/system/nexus.service templates/nexus.service.j2
cp /etc/nginx/sites-available/nexus templates/nexus-vhost.conf.j2
10. Создадим файл tasks/main.yml с задачами разбитый на модули:
- name: Check requirements import_tasks: "nexus_requirements.yml" - name: Install or upgrade import_tasks: "nexus_install.yml" - name: Nexus vhost proxy import_tasks: "nexus_nginx.yml" tags: - nexus_proxy - name: Nexus post install import_tasks: "nexus_post_install.yml"
11. Создадим модуль установки необходимых пакетов tasks/nexus_requirements.yml:
- name: Repo prepare 1 copy: content: "APT::Default-Release \"stable\";" dest: /etc/apt/apt.conf.d/99release - name: Repo prepare 2 apt_repository: repo: deb http://security.debian.org/debian-security stretch/updates main state: present - name: Install openjdk-8-jre apt: name: openjdk-8-jre state: present update_cache: yes
12. Создадим модуль установки и обновления nexus tasks/nexus_install.yml:
- name: Get latest nexus version uri: url: "https://download.sonatype.com/nexus/3/latest-unix.tar.gz" method: CONNECT status_code: 302 register: nexus_latest check_mode: no - name: Extract version from remote url set_fact: nexus_latest_version: "{{ nexus_latest.location | regex_search(regexp, '\\1') |first }}" vars: regexp: '^https://.*nexus-(\d+\.\d+\.\d+-\d+)-unix.tar.gz' - name: Check if nexus installed stat: path: "{{ nexus_install_dir }}/nexus" register: nexus_link - name: Extract nexus current version set_fact: nexus_version_running: "{{ nexus_link.stat.lnk_target | regex_search(regexp, '\\1') | first }}" vars: regexp: '^.*nexus-(\d+\.\d+\.\d+-\d+)' when: - nexus_link.stat.exists | default(false) - nexus_link.stat.islnk | default(false) - name: Check existing user user: name: "{{ nexus_user }}" group: "{{ nexus_group }}" shell: "/bin/false" state: present - name: Create nexus service file template: src: nexus.service.j2 dest: /etc/systemd/system/nexus.service mode: 0644 owner: root group: root notify: - nexus unit reload - name: Get latest nexus version get_url: url: "https://download.sonatype.com/nexus/3/latest-unix.tar.gz" dest: "{{ nexus_install_dir }}" - name: Package name set_fact: nexus_package: "nexus-{{ nexus_latest_version }}-unix.tar.gz" - name: First install or upgrade unarchive: src: "{{ nexus_install_dir }}/{{ nexus_package }}" dest: "{{ nexus_install_dir }}" creates: "{{ nexus_install_dir }}/nexus-{{ nexus_latest_version }}" copy: no when: ((not nexus_link.stat.exists) or (nexus_version_running != nexus_latest_version and nexus_upgrade)) and (not ansible_check_mode) #check previous installation and upgrade if nexus_upgrade = true notify: - nexus stop - name: Flush or execute current handlers meta: flush_handlers - name: Update symlinc to latest nexus version file: path: "{{ nexus_install_dir }}/nexus" src: "{{ nexus_install_dir }}/nexus-{{ nexus_latest_version }}" owner: "{{ nexus_user }}" group: "{{ nexus_group }}" state: link notify: - nexus restart - nexus wait port when: ((not nexus_link.stat.exists) or (nexus_version_running != nexus_latest_version and nexus_upgrade)) and (not ansible_check_mode) #check previous installation and upgrade if nexus_upgrade = true - name: Nexus JVM min heap lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-Xms.*" line: "-Xms{{ nexus_min_heap }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Nexus JVM max heap lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-Xmx.*" line: "-Xmx{{ nexus_max_heap }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Nexus JVM direct memory lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-XX:MaxDirectMemorySize=.*" line: "-XX:MaxDirectMemorySize={{ nexus_direct_memory }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Chown configuration and data files to nexus file: path: "{{ item }}" owner: "{{ nexus_user }}" group: "{{ nexus_group }}" recurse: yes with_items: - "{{ nexus_install_dir }}/nexus/" - "{{ nexus_install_dir }}/sonatype-work/" - name: Flush or execute current handlers meta: flush_handlers
13. Создадим модуль настройки nginx proxy для nexus tasks/nexus_nginx.yml:
- name: Create nexus site config template: src: "nexus-vhost.conf.j2" dest: "/etc/nginx/sites-available/nexus" mode: 0644 owner: root group: root notify: - reload nginx - name: Create nexus site link file: path: "/etc/nginx/sites-enabled/nexus" src: "/etc/nginx/sites-available/nexus" state: link notify: - reload nginx
14. Создадим модуль tasks/nexus_post_install.yml с выполнением шагов после установки, в данном конексте сработает только при первой установке и распечатает пароль администратора:
- name: Check if admin.password file exists stat: path: "{{ nexus_install_dir }}/sonatype-work/nexus3/admin.password" register: admin_password_file - name: Save content admin.password to var set_fact: default_admin_password: "{{ lookup('file', '{{ nexus_install_dir }}/sonatype-work/nexus3/admin.password') }}" when: admin_password_file.stat.exists - name: Display admin password to console debug: "msg={{ default_admin_password }}" when: admin_password_file.stat.exists
16. Выполним плейбук сначала с параметром Check:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D -C
17. Выполним обновление nexus:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D -e nexus_upgrade=true
18. Повторно выполним playbook чтобы удостовериться, что больше никакие изменения вноситься не будут.
Лекция 7. Установка и обновление gitlab через ansible
1. Модифицируем файл hosts.txt из ~/testbook, где 192.168.0.40 ваш IP-адрес:
[nginx] 192.168.0.40 [nexus] 192.168.0.40 [gitlab] 192.168.0.40
2. Создадим роль playbook/roles/gitlab со следующей структурой: defaults, handlers, tasks, templates
3. Создадим файл с начальными установками defaults/main.yml:
gitlab_server_name: 'gitlab.develop.local' gitlab_full_url: 'http://{{ gitlab_server_name }}' gitlab_web_user: 'www-data' gitlab_nginx_enabled: 'false' gitlab_upgrade: false
4. Создадим обработчики handlers/main.yml, которые потребуются в ходе исполнения задач:
- name: reconfigure gitlab command: gitlab-ctl reconfigure
5. Создадим основной файл с задачами handlers/main.yml:
- name: Install prerequisites apt: name: - curl - sudo state: present - name: Add gitlab repo apt_repository: repo: deb https://packages.gitlab.com/gitlab/gitlab-ce/debian/ bookworm main state: present filename: gitlab_gitlab-ce - name: Add Gitlab key apt_key: url: https://packages.gitlab.com/gpg.key state: present - name: Gather packages list package_facts: manager: "auto" - name: Install or upgrade Gitlab apt: name: gitlab-ce state: latest update_cache: true when: "'gitlab-ce' not in ansible_facts.packages or gitlab_upgrade" - name: Create gitlab.rb config file template: src: "gitlab.rb.j2" dest: "/etc/gitlab/gitlab.rb" mode: 0600 owner: root group: root notify: - reconfigure gitlab - name: Create gitlab site config template: src: "gitlab-vhost.conf.j2" dest: "/etc/nginx/sites-available/gitlab" mode: 0644 owner: root group: root notify: - reload nginx - name: Create gitlab site link file: path: "/etc/nginx/sites-enabled/gitlab" src: "/etc/nginx/sites-available/gitlab" state: link notify: - reload nginx
6. Создадим шаблон для конфигурационного файла gitlab с именем templates/gitlab.rb.j2:
external_url '{{ gitlab_full_url }}' web_server['external_users'] = ['{{ gitlab_web_user }}'] nginx['enable'] = {{ gitlab_nginx_enabled }}
7. Создадим шаблон для nginx proxy для gitlab с именем templates/gitlab-vhost.conf.j2:
upstream gitlab-workhorse { server unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket; } server { server_name {{ gitlab_server_name }}; server_tokens off; ## Don't show the nginx version number, a security best practice root /opt/gitlab/embedded/service/gitlab-rails/public; access_log /var/log/nginx/gitlab_access.log; error_log /var/log/nginx/gitlab_error.log; location / { client_max_body_size 0; gzip off; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://gitlab-workhorse; } }
8. Добавим в infra playbook, выполнение роли gitlab:
- hosts: nginx become: true roles: - nginx - hosts: nexus become: true roles: - nexus - hosts: gitlab become: true roles: - gitlab
9. Выполним плейбук сначала с параметром Check:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D -C
17. Выполним обновление gitlab:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D -e gitlab_upgrade=true
18. Повторно выполним playbook чтобы удостовериться, что больше никакие изменения вноситься не будут.
Лекция 8. Установка gitlab-runner через ansible
1. Модифицируем файл hosts.txt из ~/testbook, где 192.168.0.40 ваш IP-адрес:
[nginx]
192.168.0.40
[nexus]
192.168.0.40
[gitlab]
192.168.0.40
[runner]
192.168.0.40
2. Создадим роль playbook/roles/gitlab-runner со следующей структурой: defaults, handlers, tasks, templates
3. Создадим файл с начальными установками defaults/main.yml:
runner_volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/cache"
runner_extra_hosts:
- "gitlab.develop.local:192.168.0.40"
- "nexus.develop.local:192.168.0.40"
4. Создадим обработчики handlers/main.yml, которые потребуются в ходе исполнения задач:
- name: restart gitlab-runner systemd: name: gitlab-runner.service state: restarted
5. Создадим основной файл с задачами handlers/main.yml:
- name: Add gitlab-runner repo
apt_repository:
repo: deb https://packages.gitlab.com/runner/gitlab-runner/debian/ bookworm main
state: present
filename: runner_gitlab-runner
- name: Add Gitlab key
apt_key:
url: https://packages.gitlab.com/gpg.key
state: present
- name: Install or upgrade Gitlab
apt:
name:
- gitlab-runner
- python-gitlab
state: present
update_cache: yes
- name: Add gilab-runner user to docker group
user:
name: gitlab-runner
groups: docker
append: yes
- name: Remove obsolete .bash_logout file from gitlab-runner
file:
path: "/home/gitlab-runner/.bash_logout"
state: absent
- name: Create gitlab-runner config file
template:
src: "config.toml.j2"
dest: "/etc/gitlab-runner/config.toml"
mode: 0600
owner: root
group: root
notify:
- restart gitlab-runner
- name: "Register shell runner"
gitlab_runner:
api_url: "{{ gitlab_full_url }}"
api_token: "{{ gitlab_api_token }}"
registration_token: "{{ shell_register_token }}"
description: Test Shell runner
state: present
active: True
access_level: not_protected
tag_list: ['shell']
run_untagged: False
locked: True
when: not ansible_check_mode
- name: "Docker runner"
gitlab_runner:
api_url: "{{ gitlab_full_url }}"
api_token: "{{ gitlab_api_token }}"
registration_token: "{{ docker_register_token }}"
description: Docker runner
state: present
active: True
access_level: not_protected
tag_list: ['docker']
run_untagged: False
locked: True
when: not ansible_check_mode
6. Создадим шаблон для конфигурационного файла gitlab-runner с именем templates/comfig.toml.j2:
concurrent = 1
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "Test Shell runner"
url = "{{ gitlab_full_url | default('no host') }}"
token = "{{ shell_register_token }}"
executor = "shell"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[[runners]]
name = "Docker runner"
url = "{{ gitlab_full_url | default('no host')}}"
token = "{{ docker_register_token }}"
executor = "docker"
[runners.custom_build_dir]
[runners.docker]
tls_verify = false
image = "alpine:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = [{% for volume in runner_volumes %}"{{ volume }}"{{ ", " if not loop.last }}{% endfor %}]
shm_size = 0
extra_hosts = [{% for host in runner_extra_hosts %}"{{ host }}"{{ ", " if not loop.last }}{% endfor %}]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
7. Создадим роль docker и задачу playbook/roles/docker/tasks/main.yml со следующим содержанием:
- name: Add Docker repo
apt_repository:
repo: deb https://download.docker.com/linux/debian bookworm stable
state: present
filename: docker
- name: Add Docker key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: Install or upgrade Gitlab
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
update_cache: true
8. Добавим в infra playbook, выполнение ролей docker и gitlab-runner:
- hosts: nginx
become: true
roles:
- nginx
- hosts: nexus
become: true
roles:
- nexus
- hosts: gitlab
become: true
roles:
- gitlab
- hosts: runner
become: true
roles:
- docker
- gitlab-runner
9. Создадим файлы с дополнительными переменными в group_vars/{gitlab.yml, nexus.yml, tokens.yml}
10. gitlab.yml содержит следующие переменные:
gitlab_server_name: 'gitlab.develop.local'
gitlab_full_url: 'http://{{ gitlab_server_name }}/'
runner_extra_hosts:
- "gitlab.develop.local:192.168.0.40"
- "nexus.develop.local:192.168.0.40"
11. nexus.yml содержит следующие переменные:
nexus_hostname: "nexus.develop.local"
12. Создадим файл с защищенными переменными:
ansible-vault create group_vars/tokens.yml
13. Добавим следующие переменные:
shell_register_token: {{ YOUR VALUE }} docker_register_token: {{ YOUR VALUE }} gitlab_api_token: {{ YOUR VALUE }}
Значения первых двух переменных можно посмотреть в конфигурационном файле /etc/gitlab-runner/config.toml, либо в gitlab настройках, вкладка runners (под администратором).
Значение переменной gitlab_api_token, необходимо сгенерировать зайдя в gitlab под администратором(root) по адресу http://gitlab.develop.local/profile/personal_access_tokens, где необходимо сгенерировать токен с флагом "api".
14. Выполним проверку с параметром Check, где параметр vault-id запрашивает пароль у пользователя от хранилища, а -e считывает дополнительные переменные в данном случае зашифрлованные:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D -C --vault-id @prompt -e @group_vars/tokens.yml
15. Выполним infra playbook:
ansible-playbook -i hosts.txt playbook/infra.yml -K -D --vault-id @prompt -e @group_vars/tokens.yml
16. Повторно выполним playbook чтобы удостовериться, что больше никакие изменения вноситься не будут.
Лекция 9. Тестирование playbook на новой системе
1. Установим "чистую" операционную систему Debian Bookworm в виртуальную машину VirtualBox или KVM. Запишите IP-адрес виртуальной машины и проверьте доступность подключения с управляющего хоста (там где выполняются плейбуки) по ssh. В случае если IP-адрес доступен на прямую на 22-м порту, нужно указать только его, если же ипользуется тип сети NAT, то нужно организовать проброс портов из виртуальной машины, на 127.0.0.1, например, на 2200.
2. Создадим новый файл hosts_demo.txt из ~/testbook, где 127.0.0.1 ваш IP-адрес, а ansible_port - порт гостевой ОС (при условии что порт не стандартный):
[all:vars] ansible_port=2200 [nginx] 127.0.0.1 [nexus] 127.0.0.1 [gitlab] 127.0.0.1 [runner] 127.0.0.1
2. Изменим файл playbook/infra.yml следующим образом:
- hosts: nginx become: true roles: - base - nginx - hosts: nexus become: true roles: - base - nginx - nexus - hosts: gitlab become: true roles: - base - nginx - gitlab - hosts: runner become: true roles: - base - docker - gitlab-runner
3. Добавим новую роль base, задачу запишем в файл playbook/roles/base/tasks/main.yml:
- name: Install host requirements apt: name: - python-apt state: present update_cache: yes check_mode: no
4. Изменим файл playbook/roles/docker/tasks/main.yml:
- name: Add Docker repo apt_repository: repo: deb https://download.docker.com/linux/debian bookworm stable state: present filename: docker update_cache: no - name: Add Docker key apt_key: url: https://download.docker.com/linux/debian/gpg state: present - name: Install docker apt: name: - docker-ce - docker-ce-cli - containerd.io state: present update_cache: true when: not ansible_check_mode
5. Изменим файл playbook/roles/gitlab-runner/defaults/main.yml:
runner_volumes: - "/var/run/docker.sock:/var/run/docker.sock" - "/cache" runner_extra_hosts: - "gitlab.develop.local:192.168.0.40" - "nexus.develop.local:192.168.0.40" register_runners: false
6. Изменим файл playbook/roles/gitlab-runner/tasks/main.yml:
- name: Add gitlab-runner repo apt_repository: repo: deb https://packages.gitlab.com/runner/gitlab-runner/debian/ bookworm main state: present filename: runner_gitlab-runner update_cache: no - name: Add Gitlab key apt_key: url: https://packages.gitlab.com/gpg.key state: present - name: Install or upgrade Gitlab apt: name: - gitlab-runner - python-gitlab state: present update_cache: yes when: not ansible_check_mode - name: Add gilab-runner user to docker group user: name: gitlab-runner groups: docker append: yes - name: Remove obsolete .bash_logout file from gitlab-runner file: path: "/home/gitlab-runner/.bash_logout" state: absent - name: Create gitlab-runner config file template: src: "config.toml.j2" dest: "/etc/gitlab-runner/config.toml" mode: 0600 owner: root group: root notify: - restart gitlab-runner - name: "Register shell runner" gitlab_runner: api_url: "{{ gitlab_full_url }}" api_token: "{{ gitlab_api_token }}" registration_token: "{{ shell_register_token }}" description: Test Shell runner state: present active: True access_level: not_protected tag_list: ['shell'] run_untagged: False locked: True when: not ansible_check_mode and register_runners - name: "Docker runner" gitlab_runner: api_url: "{{ gitlab_full_url }}" api_token: "{{ gitlab_api_token }}" registration_token: "{{ docker_register_token }}" description: Docker runner state: present active: True access_level: not_protected tag_list: ['docker'] run_untagged: False locked: True when: not ansible_check_mode and register_runners
7. Изменим файл playbook/roles/gitlab/tasks/main.yml:
- name: Install prerequisites apt: name: - curl - sudo state: present - name: Add gitlab repo apt_repository: repo: deb https://packages.gitlab.com/gitlab/gitlab-ce/debian/ bookworm main state: present filename: gitlab_gitlab-ce update_cache: no - name: Add Gitlab key apt_key: url: https://packages.gitlab.com/gpg.key state: present - name: Gather packages list package_facts: manager: "auto" - name: Install or upgrade Gitlab apt: name: gitlab-ce state: latest update_cache: true when: "('gitlab-ce' not in ansible_facts.packages or gitlab_upgrade) and not ansible_check_mode" - name: Create gitlab.rb config file template: src: "gitlab.rb.j2" dest: "/etc/gitlab/gitlab.rb" mode: 0600 owner: root group: root notify: - reconfigure gitlab - name: Flush or execute current handlers meta: flush_handlers - name: Create gitlab site config template: src: "gitlab-vhost.conf.j2" dest: "/etc/nginx/sites-available/gitlab" mode: 0644 owner: root group: root notify: - reload nginx - name: Create gitlab site link file: path: "/etc/nginx/sites-enabled/gitlab" src: "/etc/nginx/sites-available/gitlab" state: link notify: - reload nginx when: not ansible_check_mode - name: Add or replace /etc/hosts gitlab record lineinfile: path: "/etc/hosts" line: "{{ ansible_default_ipv4.address }}\t{{ gitlab_server_name }}" state: present
8. Изменим файл playbook/roles/nexus/tasks/nexus_install.yml:
- name: Get latest nexus version uri: url: "https://download.sonatype.com/nexus/3/latest-unix.tar.gz" method: CONNECT status_code: 302 register: nexus_latest check_mode: no - name: Extract version from remote url set_fact: nexus_latest_version: "{{ nexus_latest.location | regex_search(regexp, '\\1') |first }}" vars: regexp: '^https://.*nexus-(\d+\.\d+\.\d+-\d+)-unix.tar.gz' - name: Check if nexus installed stat: path: "{{ nexus_install_dir }}/nexus" register: nexus_link - name: Extract nexus current version set_fact: nexus_version_running: "{{ nexus_link.stat.lnk_target | regex_search(regexp, '\\1') | first }}" vars: regexp: '^.*nexus-(\d+\.\d+\.\d+-\d+)' when: - nexus_link.stat.exists | default(false) - nexus_link.stat.islnk | default(false) - name: Check nexus group group: name: nexus state: present - name: Check existing user user: name: "{{ nexus_user }}" group: "{{ nexus_group }}" shell: "/bin/false" state: present - name: Create nexus service file template: src: nexus.service.j2 dest: /etc/systemd/system/nexus.service mode: 0644 owner: root group: root notify: - nexus unit reload - name: nexus enable systemd unit systemd: daemon-reload: yes name: nexus.service enabled: yes - name: Get latest nexus version get_url: url: "https://download.sonatype.com/nexus/3/latest-unix.tar.gz" dest: "{{ nexus_install_dir }}" - name: Package name set_fact: nexus_package: "nexus-{{ nexus_latest_version }}-unix.tar.gz" - name: First install or upgrade unarchive: src: "{{ nexus_install_dir }}/{{ nexus_package }}" dest: "{{ nexus_install_dir }}" creates: "{{ nexus_install_dir }}/nexus-{{ nexus_latest_version }}" copy: no when: ((not nexus_link.stat.exists) or (nexus_version_running != nexus_latest_version and nexus_upgrade)) and (not ansible_check_mode) #check previous installation and upgrade if nexus_upgrade = true notify: - nexus stop - name: Flush or execute current handlers meta: flush_handlers - name: Update symlinc to latest nexus version file: path: "{{ nexus_install_dir }}/nexus" src: "{{ nexus_install_dir }}/nexus-{{ nexus_latest_version }}" owner: "{{ nexus_user }}" group: "{{ nexus_group }}" state: link notify: - nexus restart - nexus wait port when: ((not nexus_link.stat.exists) or (nexus_version_running != nexus_latest_version and nexus_upgrade)) and (not ansible_check_mode) #check previous installation and upgrade if nexus_upgrade = true - name: Nexus JVM min heap lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-Xms.*" line: "-Xms{{ nexus_min_heap }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Nexus JVM max heap lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-Xmx.*" line: "-Xmx{{ nexus_max_heap }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Nexus JVM direct memory lineinfile: dest: "{{ nexus_install_dir }}/nexus/bin/nexus.vmoptions" regexp: "^-XX:MaxDirectMemorySize=.*" line: "-XX:MaxDirectMemorySize={{ nexus_direct_memory }}" notify: - nexus restart - nexus wait port when: not ansible_check_mode - name: Chown configuration and data files to nexus file: path: "{{ item }}" owner: "{{ nexus_user }}" group: "{{ nexus_group }}" recurse: yes with_items: - "{{ nexus_install_dir }}/nexus/" - "{{ nexus_install_dir }}/sonatype-work/" - name: Flush or execute current handlers meta: flush_handlers
9. Изменим файл playbook/roles/nexus/tasks/nexus_nginx.yml:
- name: Create nexus site config template: src: "nexus-vhost.conf.j2" dest: "/etc/nginx/sites-available/nexus" mode: 0644 owner: root group: root notify: - reload nginx - name: Create nexus site link file: path: "/etc/nginx/sites-enabled/nexus" src: "/etc/nginx/sites-available/nexus" state: link notify: - reload nginx when: not ansible_check_mode
10. Изменим файл playbook/roles/nexus/tasks/nexus_post_install.yml:
- name: Check if admin.password file exists stat: path: "{{ nexus_install_dir }}/sonatype-work/nexus3/admin.password" register: admin_password_file - name: Save content admin.password to var slurp: src: '{{ nexus_install_dir }}/sonatype-work/nexus3/admin.password' register: default_admin_password when: admin_password_file.stat.exists - name: Display admin password to console debug: "msg={{ default_admin_password['content'] | b64decode }}" when: admin_password_file.stat.exists
11. Изменим файл playbook/roles/nexus/tasks/nexus_requirements.yml:
- name: Repo prepare 1 copy: content: "APT::Default-Release \"stable\";" dest: /etc/apt/apt.conf.d/99release - name: Repo prepare 2 apt_repository: repo: deb http://security.debian.org/debian-security stretch/updates main state: present - name: Install openjdk-8-jre apt: name: openjdk-8-jre state: present update_cache: yes when: not ansible_check_mode
12. Выполним проверку с параметром Check, для новой inventory группы, плейбук должен завершиться без ошибок:
ansible-playbook -i hosts_demo.txt playbook/infra.yml -K -D --vault-id @prompt -e @group_vars/tokens.yml
13. Выполним infra playbook и применим изменения на новом хосте:
ansible-playbook -i hosts_demo.txt playbook/infra.yml -K -D --vault-id @prompt -e @group_vars/tokens.yml
14. Повторно выполним playbook чтобы удостовериться, что больше никакие изменения вноситься не будут.