Перейти к основному содержимому

Часть 2. Продвинутая работа с Docker

Настройка базы данных

docker run --rm -d \
-v mysql:/var/lib/mysql \
-v mysql_config:/etc/mysql \
--name mysql \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=blog \
--net cluster \
mysql

Подключимся к рабочей базе и создадим таблицу

docker exec -it mysql mysql -p
# Вводим пароль из переменной MYSQL_ROOT_PASSWORD, который мы сами задали

Создадим табличку posts в базе blog

CREATE TABLE blog.posts (
id INT NOT NULL AUTO_INCREMENT,
title varchar(255),
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);

Выйдем из контейнера с помощью ctrl + D

Запускаем Adminer

Запустим Adminer в той же сети

docker run -d -p 8080:8080 --net cluster --name adminer adminer

Подключимся к http://127.0.0.1:8080/ (или IP вашей ВМ, если у вас бридж-сеть).

В открывшемся интерфейсе подключимся к базе, указав:

ПолеЗначениеПримечание
Серверmysqlимя контейнера с СУБД
Имя пользователяroot
Парольpassword
База данныхblog

Если все прошло успешно, вы увидете нашу таблицу posts. Перейдем в нее и добавим несколько записей с помощью "Новая запись". Можно указывать только поле title, т.к. остальные поля генерятся автоматически при создании объекта.

При желании можно создасть записи и с помощью SQL через контейнер с mysql или через SQL-запрос в Adminer:

INSERT INTO blog.posts (title)
VALUES ("First Post"), ("Second Post"), ("Third Post");

Запускаем свой сервис

Загрузим себе материалы лабораторной:

git clone https://gitlab.com/tlakatlekutl/devops-lab2 && cd devops-lab2

В каталоге code/ находится пример примитивного API сервиса на Golang. Для того чтобы начать с ним работать, необходимо собрать образ. Для этого воспользуемся следующей командой:

docker build -t step1 -f step1.Dockerfile code/

где:

  • опция -t задает имя образа, иначе имя будет равно ID образа
  • опция -f указывает путь к Dockerfile, если ее не указывать докет будет искать файл Dockerfile в текущем каталоге
  • code/ - это конекст для сборки образа, все файлы, которые долны быть доступны во время сборки.

Запустим наш сервис (собранный ранее образ step1), передадим ему параметры подключения к базе через переменные окружения (с помощью опции -e), а также подключим его к контейнеру mysql.

docker run --net cluster -p 8000:8000 -e MYSQL_DB=blog -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASS=password step1

Проверим работу нашего приложения выполнив команду curl, в ответе должны увидеть json массив с созданными постами.

curl localhost:8000/posts

Подробнее про сборку образа

Рассмотрим структуру Dockerfile на примере step1.Dockerfile.

В начале любого образа должен быть указан базовый образ, на основе которого собирается новый. В нашем случае FROM golang:1.19.1, самый базовый возможно образ FROM scratch, в нем нет ничего.

COPY копирует файл из контекста (папочки, которою вы указываете при docker build) в указанное место в образе. Команда создает новый слой в образе;

RUN команда - запускает команду в образе, создает новый слой;

Остальные операнды либо создают пустой слой, либо напрямую меняют метаинформацию в образе.

EXPOSE показывает докеру, какие порты слушает приложение; CMD Задает команду запуска в контейнере; WORKDIR меняет рабочую директорию; USER меняет пользователя, под которым идет работа; ENV задает переменные окружения; и т.д. Подробнее можно ознакомиться в официальной документации.

Взглянем на получившиеся слои у образа:

docker history step1

Как было показано на лекции, каждый получившийся слой - это архив с измененными файлами.

Оптимизируем сборку

Для удобства вынесем переменные окружения в отдельный файл, например config.env:

MYSQL_DB=blog
MYSQL_HOST=mysql
MYSQL_USER=root
MYSQL_PASS=password

Соберем образ step2:

docker build -t step2 -f step2.Dockerfile code/

Запустим образ step2 и проверим, что он работает, аналогично предыдущему:

docker run --link mysql -p 8000:8000 --env-file=config.env  step2

Задание: Сравните образы step1 и step2 (их Dockerfile и history) и опишите различия.

Многоэтапная сборка

Вы могли заметить, что для работы нашего сервиса необходим только исполняемый файл, тогда возникает вопрос "А зачем нам тащить с собой сборочные зависимости?" Да не нужны они, поэтому существует многоэтапная сборка: вы собираете исполняемый файл в отдельном образе, а затем копируете результат в эксплуатируемый образ.

Соберем, запустим и протестируем образ step3

docker build -t step3 -f step3.Dockerfile code/
docker run --link mysql -p 8000:8000 --env-file=config.env step3

Задание: Взгляните на step3.Dockerfile, в чем принципиальное отличие от предыдущих докерфайлов? Оцените docker history.

Делимся образом - docker push

Для ознакомления:

# Авторизируемся где-нибудь на приватном registry
docker login

# Смотрим что за образ мы хотим загрузить
docker images

# Тэгаем
docker tag XXX:VERSION registry-gitlab.com/user_or_group/XXX:VERSION

# Загружаем
docker push registry-gitlab.com/user_or_group/XXX:VERSION