Skip to content

Latest commit

 

History

History
363 lines (315 loc) · 26.9 KB

Lab_N1.md

File metadata and controls

363 lines (315 loc) · 26.9 KB

Лабораторная работа №1

Знакомство с docker


Что такое контейнеры?

Прежде чем рассказывать про Docker, нужно сказать несколько слов о технологии контейнеризации.

  • Контейнеры — это способ упаковать приложение и все его зависимости в единый образ. Этот образ запускается в изолированной среде, не влияющей на основную операционную систему. Контейнеры позволяют отделить приложение от инфраструктуры: разработчикам не нужно задумываться, в каком окружении будет работать их приложение, будут ли там нужные настройки и зависимости. Они просто создают приложение, упаковывают все зависимости и настройки в единый образ. Затем этот образ можно запускать на других системах, не беспокоясь, что приложение не запустится.

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

Контейнеризация похоже на виртуализацию, но это не одно и то же. Виртуализация работает как отдельный компьютер, со своим виртуальным оборудованием и операционной системой. При этом внутри одной ОС можно запустить другую ОС. В случае контейнеризации виртуальная среда запускается прямо из ядра основной операционной системы и не виртуализирует оборудование. Это означает, что контейнер может работать только в той же ОС, что и основная. При этом так как контейнеры не виртуализируют оборудование, они потребляют намного меньше ресурсов.

преимущество использования Docker:

  • Изоляция запущенных приложений. Можно отделить ваше приложение от ОС хоста и от других приложений;
  • Облегчение процесса разработки, тестирования и развертывания приложений;
  • Нет необходимости в конфигурации среды для запуска – она поставляется вместе с приложением.

Компоненты Docker

Выделим важные компоненты docker:

  • Docker image (докер-образ) - это неизменяемый образ, из которого разворачивается контейнер. Его можно рассматривать как набор файлов, необходимых для запуска и работы приложения на другом хосте. Говоря простыми словами, образ Docker это образ, содержащий внутри себя приложение и все зависимости, необходимые для запуска этого приложения в Docker;
  • Docker registry - это репозиторий, в котором хранятся образы. Пример: DockerHub,
  • Dockerfile (докер-файл) - это файл-инструкция для сборки образа;
  • Docker container (докер-контейнер) - это запущенный экземпляр образа Docker;
  • Docker host (докер-хост) - машина с установленным docker;
  • Docker daemon (докер-демон) - Это фоновый процесс, который работает постоянно и ожидает команды. Все операции по управлению контейнерами отправляются именно в демон, например: запустить или остановить контейнер, скачать образ. И уже на основе этих команд демон выполняет необходимые действия с контейнерами и образами. Поэтому докер-демон знает все о контейнерах, запущенных на одном хосте: сколько всего контейнеров, какие из них работают, где хранятся образы и так далее;
  • Docker client (докер-клиент) - это клиент, при помощи которого пользователи взаимодействуют с демоном и отправляют ему команды.

image-1

Установка Docker (linux)


Перед установкой проверьте архитектуру процессора введя следующую команду:

uname -m

Установим дополнительные пакеты:

sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Добавим официальный ключ GPG от репазитория к установке докера (команду следуюет запустить из под рут пользователя):

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

В зависимости от архитектуры, добавим соответствующий репазиторий в ubuntu (команду следуюет запустить из под рут пользователя):

  • x86_64 / amd64

    echo \
    "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • armhf

    echo \
    "deb [arch=armhf signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • arm64

    echo \
    "deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • s390x

    echo \
    "deb [arch=s390x signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Установка Docker Engine:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

Проверим установку докера:

$ sudo docker --version
Docker version 20.10.8, build 3967b7d

!Важно: если не удалось выполнить последнюю команду, скорее всего установка было выполнена не по инструкции. Попробуйте пройти все пути под root пользователем: sudo su.

Добавим нашего пользователя в docker group (чтобы не использовать команду sudo):

# Создадим группу
sudo groupadd docker
# Добавим текущего пользователя в группу
sudo usermod -aG docker $USER

Для дальнейшей работы без sudo, необходимо перезапустить машину.

Установка Docker Compose (linux)


Выполните эту команду, чтобы загрузить текущую стабильную версию Docker Compose:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Примените разрешение на запуск бинарного файла (убедитесь, что файл существует):

sudo chmod +x /usr/local/bin/docker-compose

Проверим установку:

$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Практическая часть (Docker)


Запустим первый контейнер hello-world, для этого воспользуемся следующей командой:

docker run hello-world
# docker run - команда для заупска
# hello-world - это название образа, который мы хотим запустить

Опишем что же произошло при запуске команды. Первым делом, docker deamon получил от нас команду и попытался запустить контейнер. Образ для контейнера не был обнаружен на локальном устройстве (docker host). Поэтому docker deamon сначала скачал образ из DockerHub репозитория и затем его запустил.

Проверим список контейнеров:

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

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

$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
9924379be34d   hello-world   "/hello"   3 minutes ago   Exited (0) 2 minutes ago             elastic_kilby

Из полученного ответа видно, что статус контейнера Exited 0. Контейнер запустил внутри себя команду, программа отработала, и контейнер завершил свою работу. Это стандартная работа контейнера. Контейнер находится в активном состоянии только при условии, что запущенное в нем приложение работает.

Попробуем сделать тоже самое с образом Busybox. Для начала, запустите следующую команду:

docker pull busybox

Команда pull скачивает образ busybox из регистра Докера и сохраняет его локально. Можно использовать команду docker images, чтобы посмотреть список образов в системе:

$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
busybox       latest    42b97d3c2ae9   2 weeks ago    1.24MB
hello-world   latest    d1165f221234   6 months ago   13.3kB

Запустим контейнер:

docker run busybox

Ничего не произошло! Баг? На самом деле - нет. Под капотом произошло много всего. Докер-клиент нашел образ (в нашем случае, busybox), запустил контейнер и запустил команду внутри этого контейнера. Мы сделали docker run busybox, но не указали никаких команд, так что контейнер загрузился, запустилась пустая команда и программа завершилась. Передадим при запуске контейнера команду:

$ docker run busybox echo "Hello, TCS!"
Hello, TCS!

Теперь все выглядит корректно. Почему при запуске контейнера hello-world небыло необходимости в передаче команды? Дело в том, что при создании образа, в контейнерах всегда устанавливается команда запуска. В образе hello-world использовалась команда, по выводу в консоль сообщения приветствия. В образе же busybox используется команда sh (являющаяся также командной оболочкой, вместо нее иногда можно использовать оболочку bash).

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

docker run -it busybox bash
# Передаем в запуск команду sh (она же - командная оболочка)

Попробуем внутри него создать файл:

$ touch test.txt
$ ls -alh
total 44K    
drwxr-xr-x    1 root     root        4.0K Sep  4 19:57 .
drwxr-xr-x    1 root     root        4.0K Sep  4 19:57 ..
-rw-r--r--    1 root     root           0 Sep  4 19:57 test.txt
...

Видим, что файл test.txt создался. И вместе с этим файлом мы можем наблюдать другие внутренние файлы запущенного контейнера. Попробуем выйти из контейнера и зайти в него заново. Проверим, остался ли файл.

$ exit
$ docker run -it busybox bash
$ ls -alh

Видим, что файла больше нету. На самом деле, мы не вернулись в прошлый контейнер. Мы создали новый и перешли в него. Предыдущий контейнер также остался в памяти, но он находится в состоянии exit 0. Мы можем повторно вернуть в консоль предыдущего контейнера выполнив следующую команду:

# Просмотрим список всех контейнеров, и скопируем его id:
$ docker ps -a
# Запустим остановленный контейнер
$ docker start 117fe8525a25
# Проверим список запущенных контейнеров
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS          PORTS     NAMES
117fe8525a25   busybox   "sh"      13 minutes ago   Up 12 seconds             determined_banach
# Подключимся к консоли контейнера
$ docker attach 117fe8525a25
# Проверим, имеется ли файл в контейнере
$ ls -alh
total 44K    
drwxr-xr-x    1 root     root        4.0K Sep  4 19:57 .
drwxr-xr-x    1 root     root        4.0K Sep  4 19:57 ..
-rw-r--r--    1 root     root           0 Sep  4 19:57 test.txt
...

Что означают новые команды? Для того, чтобы опсать команду start, необходимо разобраться в команде run. Команда run содержит в себе последовательный запуск следующих команд: create + start. Так как контейнер уже был создан, оставалось его только запустить. Команда attach необходима для того, чтобы подключиться к консоли контейнера. На самом деле, команду run никогда не используют в отдельности, чаще всего использую run или другие способы управления контейнером, о котором поговорим чуть позже.

Попробуем теперь удалить контейнер. Для этого необходимо воскользоваться командой:

# запустим контейнер еще раз
$ docker start 117fe8525a25
# остановим контейнер
$ docker kill 117fe8525a25
# удалим контейнер
$ docker rm 117fe8525a25
# удалим образ
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
busybox      latest    42b97d3c2ae9   2 weeks ago   1.24MB
$ docker rmi 42b97d3c2ae9

Для задания автоматического удаления контейнера, после его остановки, необходимо указать команду:

docker run --rm busybox echo "Hello, TCS!"

Практическая часть (Docker-compose)


Для упрощения работы с docker существуют много различных инструментов. Одним из популярных является docker-compose. Docker-compose - это приложение написанное на python, предназначено для решения задач, связанных с развёртыванием проектов. Он использует заранее подготовленные docker-compose.yml с описанными инструкциями по запуску контейнеров (контейнеров может быть несколько).

Рассмотрим пример. В качестве примера возьмем существенное приложение, такое как Prometheus.

Перейдем в пустую директорию и создадим в ней docker-compose.yml файл со следующим содержимым:

version: '3.9'

services:
  prometheus:
    image: prom/prometheus:latest
    restart: always
    ports:
      - 9090:9090

Что указано в данном файле?

  • version - это версия приложения docker-compose;
  • services - под этим значением передаются списки всех приложений (на текущий момент приложение одно, приложение prometheus);
  • image - образ приложения prometheus (образ публичный, берется из dockerHub репозитория);
  • restart - политика перезапуска контейнера (always означает, что если в приложении возникнет ошибка, контейнер перезапустится);
  • ports - список портов, которые нам необходимо прокинуть из контейнера во вне.

Запустим контейнер с помощью команды:

# необходимо находиться в директории с файлом docker-compose.yml
docker-compose up -d

Перейдем в браузер по адресу http://localhost:9090 и мы увидем интерфейс приложения, запущенного в контейнере.

Попробуем перейти внутрь контейнера, для этого необходимо воспользоваться командой:

docker exec -it b07c21eed688 sh

Теперь вы находитесь внутри контейнера и можете его исследовать. Как и у большинства приложений, prometheus умеет отображать свои логи (перед этим не забудьте выйти из консоли контейнера). Для отображения логов, необходимо воспользоваться командой:

$ docker logs b07c21eed688

Попробуем остановить приложение. Для этого необходимо воспользоваться командой:

docker-compose down

Приложение было остановлено, контейнер был удален (теперь приложение можно восстановить обратно через docker-compose up -d). Для обращения к приложению запущенного через docker-compose можно также обращаться через команды docker, так как docker-compose всего лишь внешняя оболочка для работы докером.

Практическая часть (Dockerfile)


В этом разделе мы рассмотрим примеры по написанию своих docker образов. Предположим, у нас имеется приложение написанное на языке python3 и мы хотим запустить его внутри docker контейнера. Приложение выполняет следующую функцию:

  • прослушивает внешние запросы на определенном порту;
  • при переходе из браузера на указанный порт должна отобразиться надпись приветствия: "Hello, TCS!".

Создадим пустую директорию и следующие файлы:

  • Dockerfile (файл с описание сборки docker образа)
  • docker-compose.yml (файл, используемый для заупска docker контейнера)
  • requirements.txt (файл со списком предустанавливаемых python библиотек)
  • app.py (приложение на python)

Содержимое файлов:

  • app.py
    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello, TCS!'
  • requirements.txt
    Flask==2.0.1
    
  • docker-compose.yml
    version: '3.9'
    
    services:
        flask-hello:
            image: flask-hello:latest
            restart: always
            ports:
            - 8080:8080
  • Dockerfile
    FROM python:3.8-slim-buster
    
    WORKDIR /app
    
    COPY requirements.txt requirements.txt
    RUN pip3 install -r requirements.txt
    
    COPY . .
    
    CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0", "--port=8080"]

Рассмотрим подробнее незнакомые для нас файлы:

  • requirements.txt - это стандартный файл используемый python для указания списка скачиваемых внешних библиотек. Для установки библиотек используется команда: pip3 install -r requirements.txt.
  • Dockerfile - файл описывающий последовательность для сборки образа. Рассмотрим каждый момент подробнее:
    • FROM python:3.8-slim-buster - базовый образ, который будет использоваться для сборки нашего. Для сборки уже существует множество образов с предустановленным ПО. Например, в текущем образе уже имеется заранее предустановленный python:3.8.
    • WORKDIR /app - создается папка /app внутри образа. Происходит перемещение выполнения команд в данной директории (то есть, все команды теперь запускаются из этой папки. Последующая команда копирования говорит о том, что копирование будет проходить в директорию /app).
    • COPY requirements.txt requirements.txt - копирование файла из вне внутрь образа.
    • RUN pip3 install -r requirements.txt - запуск команды по установке python3 библиотек из файла requirements.txt.
    • COPY . . - копирование всей файлов из текущей директории в образ (в директорию /app)
    • CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0", "--port=8080"] - команда запуска приложения (называется ENTRYPOINT). После создания контейнера запустится именно данная команда.
  • docker-compose.yml:
    • image: flask-hello:latest - название образа. Название будет передано в команду по сборке образа (названия должны совпадать!).

Запустим следующую команду по сборке образа:

docker build -t "flask-hello" ./

В консоли видим логи запуска команд описанных в Dockerfile файле.

Запустим приложение, используя наш собранный образ и перейдем в браузер по адресу http://localhost:8080:

docker-compose up -d

Как и с примером из приложения Prometheus, мы можем отслеживать логи приложения, для этого необходимо запустить команду:

docker logs 01d595c4d819

Практическая работа (Задание)


Задание: необходимо запустить приложение написанное с помощью библиотеки flask в docker. Приложение должно выводить на экране температуру в городе Зеленоград.