Початок роботи з Doker.

Основи роботи з Linux. -> Django и PostgreSQL с Doker.

Джаного та база даних з Docker.

джерело

Створюємо новий проект.

Файл залежностей requirements.txt

Django
psycopg2

Встановлення ВО та залежностей.

doker

Старт проекту та сервера.

doker

В даному випадку ми не застосовували міграцію і базу даних не було створено.

Тепер завдання полягає в тому, щоб не використовувати папку venv, а встановити залежності всередині образу Docker.

При цьому зробивши так, щоб усі файли проекту залишалися в локальній області для розробки та не переносились усередину контейнера.

Таким чином, все що служить для запуску проекту (оточення) буде ізольовано всередині контейнера.

Створимо файл Dockerfile.

FROM python:3.6 AS django
ENV PYTHONUNBUFFERED 1
RUN mkdir /app
WORKDIR /app
RUN apt update
RUN apt -y install libpq-dev
COPY requirements.txt /app
RUN pip install -r requirements.txt

ENV PYTHONUNBUFFERED 1 - наказує python виводити все в термінал

Запускаємо складання образу

docket build.

і спостерігаємо процес

doker

Бачимо, що просить оновити інсталятор pip.

doker

Додамо команду поновлення як просить.

...
COPY requirements.txt /app
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install -r requirements.txt

Тепер наше завдання запустити образ у контейнері.

Найпростіше це злити через docker-compose up.

Для цього потрібний файл конфігурації docker-compose.yaml.

version: '3.5'
services: 
    django:
        build: .
        restart: always
        ports:
            - 8000:8080

Запускаємо команду складання та запуску контейнера.

docker-compose up

doker

Тепер нам потрібно запустити кілька команд всередині контейнера, щоб підняти веб-сервер з джанго проектом.

Також нам необхідно зробити посилання всередині контейнера на наш каталог із проектом зовні.

version: '3.5'
services: 
    django:
        build: .
        restart: always
        ports:
            - 8000:8000
        working_dir: /app
        command: python manage.py runserver 0.0.0.0:8000
        volumes:
            - ./blog:/app

Додамо контейнер із PostgreSQL.

db:
    restart: always
    image: postgres:latest
    ports:
        - "5432:5432"
    volumes:
        - ./pg_data:/var/lib/postgresql/data/
    environment:
        - POSTGRES_USER=postgres
        - POSTGRES_PASSWORD=1q2w3e
        - POSTGRES_DB=blog

Тепер додамо файл налаштувань оточення для проекту .env.dev

DEBUG=1
SECRET_KEY=foo
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
SQL_ENGINE=django.db.backends.postgresql
SQL_DATABASE=blog
SQL_USER=postgres
SQL_PASSWORD=1q2w3e
SQL_HOST=db
SQL_PORT=5432

Увімкнемо його в контейнер.

version: '3.5'
services: 
    django:
        ...
        env_file:
            - ./.env.dev

І пропишемо коннект у settings.py

DATABASES = {
    "default": {
        "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"),
        "NAME": os.environ.get("SQL_DATABASE", os.path.join(BASE_DIR, "db.sqlite3")),
        "USER": os.environ.get("SQL_USER", "user"),
        "PASSWORD": os.environ.get("SQL_PASSWORD", "password"),
        "HOST": os.environ.get("SQL_HOST", "localhost"),
        "PORT": os.environ.get("SQL_PORT", "5432"),
    }
}

Перезбираємо контейнери.

docker-compose up --build

Проводимо міграцію.

docker-compose exec django python manage.py migrate --noinput

Точка входу для образу

Використовується для запуску скрипта під час кожного запуску образу.

Наприклад, якщо ми хочемо застосовувати міграцію щоразу, коли запускаємо образ створимо файл entrypoint.sh.

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

python manage.py flush --no-input
python manage.py migrate

exec "$@"

І хобуємо його в образ.

FROM python:3.6 AS python36
...
RUN mkdir /entry
COPY entrypoint.sh /entry
ENTRYPOINT ["/entry/entrypoint.sh"]

Якщо потрібно використовувати різні Dockerfile для контейнерів.

services:
  service1:
    build:
        context: .
        args:
            - NODE_ENV=local
        dockerfile: Dockerfile_X
    ports:
        - "8765:8765"

Корисні команди

Видалення контейнерів.

docker-compose down -v

Перегляд списку запущених контейнерів

docker ps

Видалити контейнер

docker-compose rm db

Nginx с Doker.

Встановимо проксі-сервер nginx apache з можливістю керувати змінними оточенням.

Створимо стартову сторінку index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Docker Nginx</title>
</head>
<body>
  <h2>Hello from Nginx container</h2>
</body>
</html>

Створимо файл Dockerfile

FROM nginx:latest

Створимо збирач docker-compose.yaml

version: '3.5'
services: 
    nginx:
        build: .
        restart: always
        ports:
            - 8081:80

8000:8080 -ми перенаправляємо порт 80 зсередини контейнера назовні на 8081

Складання та запуск контейнера.

docker-compose up --build

Запуск не через збирач

docker run -it --rm -d -p 8081:80 --name web nginx

Заходимо усередину контейнера.

docker exec -ti b42580b257e2 bash

Виводимо конфігураційний файл nginx.

cat /etc/nginx/conf.d/default.conf

b42580b257e2 - ідентифікатор контейнера, його можна отримати за допомогою команди docker ps

Однак можна і явно поставити ім’я.

version: '3.5'
services: 
    nginx:
        build: .
        container_name: my-nginx

І звертатися на ім’я.

docker exec -ti my-nginx bash

Створюємо файл конфігурації nginx.conf.

server { 
 listen 80;
 server_name localhost;
 location / {
   root /app;
   try_files $uri /index.html;
 }
}

Копіюємо конфігураційний файл усередину контейнера та створюємо папку app.

FROM nginx:latest
RUN mkdir /app
COPY ./nginx.conf /etc/nginx/conf.d/default.conf

Зробимо посилання з поточної директорії усередину контейнера.

version: '3.5'
services: 
    nginx:
        build: .
        restart: always
        ports:
            - 8081:80
        volumes:
            - .:/app

Перекидання змінних оточення всередину контейнера.

version: '3.5'
services: 
    nginx:
        ...
        environment:
            - NGINX_PORT=8081

Але проблема в тому, що ці змінні з’являються тільки на етапі запуску контейнера, а не в момент складання образу.

Тому щоб змінювати щось на етапі збирання можна в конфігураційному файлі додати мітку.

server { 
 listen __NGINX_PORT__;
 ...
}

Потім її міняти під час збирання.

FROM nginx:latest
RUN mkdir /app
COPY ./default.conf /app/default.conf
RUN cat /app/default.conf | sed  "s/__NGINX_PORT__/8081/" > /etc/nginx/conf.d/default.conf

TODO: можна спробувати прапор -i

sed -i 's/VERSION/8.04/' /etc/nginx/conf.d/default.conf

Або грамотніше, через змінну, яку спочатку додамо в процес складання в docker-compose.yaml.

nginx:
    build: 
        context: .
        args:
            - NGINX_PORT=8084

А потім використовуємо.

ARG NGINX_PORT  
RUN cat /app/default.conf | sed  "s/__NGINX_PORT__/$NGINX_PORT/" > /etc/nginx/conf.d/default.conf

Flask с Doker.

Створимо стартову сторінку index.html і покладемо її до папки templates.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Docker Flask</title>
</head>
<body>
  <h2>Hello from Flask container</h2>
</body>
</html>

Створимо файл із залежностями requirements.txt.

Flask

Створимо файл Dockerfile

FROM python:3.6
RUN mkdir /app
WORKDIR /app
COPY ./requirements.txt /app/requirements.txt
RUN apt update
RUN pip install -r requirements.txt

Створимо збирач docker-compose.yaml.

version: '3.5'
services: 
    flask:
        build: 
            context: .
            dockerfile: Dockerfile-flask
        volumes:
            - .:/app

Створимо скрипт для запуску start.py.

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0')

Додамо прокидання портів.

ports:
    - 8082:5000

Додамо команду запуску.

CMD python start.py

Додамо рендеринг шаблону.

from flask import render_template

@app.route('/')
def hello_world():
    return render_template('index.html')

Проксіювання через nginx.

Створюємо файл для образу Dockerfile-nginx

FROM nginx:latest
RUN mkdir /app
COPY ./default.conf /etc/nginx/conf.d/default.conf

Конфігураційний файл.

server { 
     listen 80;
     server_name localhost;
     location / {
       proxy_pass http://flask:5000;
     }
}

Додаємо контейнер до збирача.

nginx:
    build: 
        context: .
        dockerfile: Dockerfile-nginx
    volumes:
        - .:/app
    ports:
        - 8084:80

Проксуємо статику.

<img src="/static/test.png" />

Додаємо шлях до статики у default.conf.

   ...

  location /static/ {
      alias /app/static/;
  }

   ...
Основи роботи з Linux. -> Початок роботи з Doker.

Початок роботи з Doker.

Докером (docker) називався робітник, який переносив товари на судна та назад, коли ті стояли в портах.

Там були ящики та вантажі різних розмірів та форм, і досвідчені докери цінувалися за те, що вони спроможні вручну помістити товари на кораблі економічно ефективним способом.

Найняти людей для переміщення цих вантажів було недешево, але альтернативи не було.

Це має бути знайоме всім, хто працює у сфері програмного забезпечення.

Багато часу та інтелектуальної енергії витрачається на перенесення програмного забезпечення на різні системи та сервери.

doker

На рис показано, як можна заощадити час та гроші за допомогою Docker концепції.

Коли ми купуємо потужний сервер, що складається з безлічі процесорів і пам’яті, виникає потреба його ‘розпиляти’ на дрібніші сервера.

І потім кожен сервер повісити свій процес, сайт, сервіс тощо.

Тобто. створюється гіпервізор (основна операційна система) і в нього встановлюються гостьові операційні системи (віртуальні сервери).

Кожному віртуальному серверу виділяються обмежені ресурси пам’яті процесорам тощо. Це так само робить безпечним ситуацію злому віртуального сервера, коли страждає лише він.

Docker може використовуватися для заміни віртуальних машин у багатьох ситуаціях. Якщо вас хвилює лише програма, а не операційна система, Docker може замінити віртуальну машину, а ви можете залишити турботу про операційну систему комусь іншому.

Docker не тільки швидше, ніж віртуальна машина, призначена для запуску, він легший у переміщенні, і завдяки його багаторівневій файловій системі ви можете легше та швидше ділитися змінами з іншими. Він також міцно вкорінений у командному рядку та найвищою мірою придатний для написання сценаріїв.

Якщо ви хочете швидко поекспериментувати з програмним забезпеченням, не порушуючи існуюче налаштування і не проходячи через труднощі, пов’язані з підготовкою віртуальної машини, Docker може надати “пісочницю” за мілісекунди. Звільняючий ефект цього процесу важко зрозуміти, поки ви не відчуєте його на собі.

Докер включає 2 поняття - це образ і контейнер.

Образ - це зібраний проект з урахуванням операційної системи, що містить усе необхідне його роботи.

Контейнер – це запущений, працюючий образ. Таким чином, один раз зібраний образ може бути запущений в необмеженій кількості контейнерів.

Створюючи образи у структурованому вигляді, готові до переміщення у різні середовища, Docker змушує вас явно документувати свої програмні залежності з базової точки відправлення. Навіть якщо ви вирішите не використовувати Docker всюди, ця документація

Безперервна доставка

Це парадигма доставки програмного забезпечення, заснована на конвеєрі, який перебудовує систему при кожній зміні, а потім здійснює доставку у виробництво (або “наживо”) за допомогою автоматизованого (або частково автоматизованого) процесу.

Оскільки ви можете більш точно контролювати стан середовища складання, складання Docker більш відтворювані, ніж традиційні методи складання програмного забезпечення. Це робить реалізацію безперервної доставки набагато простіше.

Установка на Ubuntu

Ставимо необхідні бібліотеки.

$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

Копіюємо GPG ключ.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Додаємо репозиторій.

sudo add-apt-repository \

“deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable”

Встановлення.

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

Ключові концепції та команди.

doker

Перш ніж запускати команди Docker, найкраще розібратися з поняттями образів, контейнерів та шарів. Коротко кажучи, контейнери запускають системи, визначені образами. Ці образи складаються з одного або декількох шарів (або наборів відмінностей) плюс деякі метадані Docker.

Основна функція Docker – створювати, відправляти та запускати програмне забезпечення у будь-якому місці, де є Docker.

Для кінцевого користувача Docker це програма з командним рядком, яку вони запускають.

docker build Зібрати образ Docker

docker run Запустити образ Docker як контейнер

docker commit Зберегти контейнер Docker як образ

docker tag Присвоїти тег образу Docker

Один із способів поглянути на образи та контейнери – це розглядати їх як програми та процеси. Так само процес може розглядатися як «додаток, що виконується», контейнер Docker може розглядатися як образ, що виконується Docker.

Якщо ви знайомі з принципами об’єктно-орієнтованого програмування, ще один спосіб поглянути на образи та контейнери – це розглядати образи як класи, а контейнери – як об’єкти.

Контейнери запускають один процес під час запуску. Коли процес завершується, контейнер зупиняється.

Наприклад, з одного образу можна запустити 3 контейнери:

  • django

  • mysql

  • nginx

Способи створення образів.

Їх є кілька.

  1. Запустити контейнер у командному рядку, вказавши його параметри у команді docker run. Потім можна перенести контейнер образ за допомогою docker commit.

Підійде якщо ви хочете перевірити, чи працює ваш просес установки.

  1. Виконати збірку з відомого базового образу, вказавши її в Dockerfile.

Dockerfile – це текстовий файл, який містить серію команд.

doker

Основні команди.

FROM : Визначає базовий образ.

COPY : Копіює файли з локальної папки в образ.

ADD :Схожа на COPY тільки розархівує у разі архіву.

RUN : Запускає команду всередині образу та зберігає всі зміни в образі, які вносить команда.

ENTRYPOINT [““, ““, …] : Конфігурує команду за замовчуванням всередині контейнера, якщо не вказано, то виконується за замовчуванням така команда /bin/sh -c .

CMD [““, …] : Визначення параметрів команди запуску, враховуючи, що за дефолтом /bin/sh -c, ми можемо до нього додати параметри через CMD.

WORKDIR

: Встановлює робочу директорію для наступних команд таких як RUN, CMD, ENTRYPOINT, COPY, та ADD.

Файл Dockerfile починається з базового образу за допомогою команди FROM. У цьому прикладі використовується образ Node.js, тому у вас є доступ до двійкових файлів Node.js. Офіційний образ Node.js називається node.

git вже встановлений у базовому образі, але це не стосується всіх образів.

WORKDIR - не тільки змінює директорію, але й визначає, в якому каталозі ви будете перебувати при запуску програми.

EXPOSE - повідомляє Docker, що контейнери із зібраного образу повинні прослуховувати цей порт.

Как видим Dockerfile – це проста послідовність обмеженого набору команд, що виконуються у строгому порядку.

Тут команда RUN впливає на файлову систему, перевіряючи та встановлюючи програми, а команди EXPOSE, CMD та WORKDIR – на метадані образи.

Складання образу.

doker

Після закінчення зборки нам видадуть остаточний ідентифікатор образу, готовий до присвоєння тега.

Successfully built 66c76cea05bb

Присвоїти тег можна командою

docker tag 66c76cea05bb mytag

Запуск контейнера з образу.

doker run -i -t -p 8000:8000 --name example1 mytag

-p - перенаправляє порт із контейнера (перший) на хост комп’ютера (другий)

Підкоманда docker diff показує, які файли торкнулися з моменту створення примірника образу як контейнера.

Іноді може виникнути помилка доступу (permisson denite) до сокету докеру. Тоді допомагає таке встановлення прав на сокет.

sudo chmod 666 /var/run/docker.sock

Слои Docker

Шари Docker допомагають подолати велику проблему, яка виникає, коли ви використовуєте контейнери в широкому масштабі.

Уявіть собі, що станеться, якщо ви запустите сотні або навіть тисячі програм, і кожній із них знадобиться копія файлів для зберігання в будь-якому місці.

Як ви можете уявити, дисковий простір закінчиться досить швидко!

doker

За промовчанням Docker внутрішньо використовує механізм копіювання під час запису, щоб зменшити обсяг потрібного дискового простору.

Стисло суть методу.

Ідея підходу copy-on-write полягає в тому, що при читанні області даних використовується спільна копія, у разі зміни даних створюється нова копія.

При створенні образу Doker створює шари файлової системи та їх використовує під час створення нових образів. Наприклад, якщо два образи використовують одну ОС Ubuntu, то вона не буде скопійована в обидва, а вони будуть використовувати один і той же шар, що містить цю операційну систему.

Архітектура Docker

doker

Виходячи з малюнка видно, що докер-образи в реєстрі ми можемо зберігати як на своєму сервері, так і на офіційному сайті Docker Hub або інших не офіційних.

Коли ми запускаємо контейнер, процес взаємодії з ним включає 2 сутності: клієнт Doker і демон Doker.

Щоразу, коли вводимо команду, ми її повідомляємо клієнту, той у свою чергу смикає демона по HTTP і повертає нам результат.

Демон – це сервер, який отримує запити та повертає відповіді від клієнта за протоколом HTTP.

У свою чергу, він відправлятиме запити до інших служб для надсилання та отримання образів, також використовуючи протокол HTTP.

Демон також відповідає за турботу про ваші образи і контейнери за лаштунками, тоді як клієнт виступає посередником між вами та інтерфейсом RESTful.

Демон Docker

Демон – це процес, який виконується у фоновому режимі режимі, а не під безпосереднім контролем користувача. Сервер – процес, який приймає запити від клієнта та відповідає.

Демони часто також є серверами, які приймають запити від клієнтів для виконання дій їм.

Команда docker – це клієнт, а демон Docker виступає як сервер, що виконує обробку ваших контейнерів та образів Docker.

Демон Docker це центр ваших взаємодій з Docker, і тому він є найкращим місцем, де ви можете почати розуміти всі відповідні елементи.

Він контролює доступ до Docker на вашому комп’ютері, керує станом контейнерів та образів, а також взаємодіє із зовнішнім світом.

Робимо доступним демон із вне.

Хоча за замовчуванням ваш демон Docker доступний тільки на вашому хості, мо- можуть бути причини, щоб дозволити іншим доступ до нього.

Хоча цей метод може бути потужним та корисним, він вважається небезпечним. Сокет Docker може бути використаний будь-ким, хто має доступ (включаючи контейнери з підключеним сокетом) Docker) для отримання привілеїв користувача root.

РІШЕННЯ - запустити демон Docker з відкритою TCP адресою.

Зупинка демона.

sudo service docker stop

Перевірити чи запущений демон докера можна так:

ps -ef | grep -E 'docker(d| -d| daemon)\b' | grep -v grep

doker

Запускаємо на сокеті.

sudo docker daemon -H tcp://0.0.0.0:2375

Ви можете підключитися зовні за допомогою наступної команди:

$ docker -H tcp://<your host's ip>:2375 <subcommand>

Запуск контейнерів як демонів

ПРОБЛЕМА

Ви хочете запустити контейнер Docker у фоновому режимі як службу.

РІШЕННЯ

Використовуйте прапорець -d у команді docker run та пов’язані прапори управління контейнерами визначення характеристик службы.

$ docker run -d -i -p 1234:1234 --name daemon ubuntu:14.04 nc -l 1234

-d - запустити контейнер як демон.

-i – дає цьому контейнеру можливість взаємодіяти з вашим сеансом Telnet.

-p - публікуємо порт 1234 із контейнера на хост

–name - зачепимо контейнеру ім’я. Давати імена контейнерам дуже корисно для присвоєння імен хостів, до яких ви можете звернутися. пізніше

nc -l 1234 - запускаємо простий ехосервер, що прослуховує, на порту 1234 за допомогою netcat (nc).

У простому випадку NetCat викликається як:

nc host port

Це призводить до створення TCP-підключення із зазначеними реквізитами та замиканням стандартного введення на мережевий висновок і навпаки, стандартного виведення на мережне введення. Така функціональність нагадує команду cat, що зумовило вибір імені netcat. У разі неможливості підключення програма виводить повідомлення про помилку на stderr.

Тепер можна підключитися до нього та надсилати повідомлення через Telnet. Ви побачите, що контейнер отримав повідомлення за допомогою команди docker logs, як показано у наступному лістингу.

doker

Зупинка контейнера.

$ docker stop blog1

Видалення контейнера

$ docker rm blog1

Список всіх запущених контейнерів.

docker ps

Стратегія перезапуску демона.

Прапор docker run - restart дозволяє застосовувати набір правил, яким необхідно дотримуватися (так звана стратегія повторного запуску), коли контейнер завершується

no - Не перезапускати при виході контейнера

always - Завжди перезапускати при виході контейнера

unless-stopped - Завжди перезавантажувати, але пам’ятати про явну зупинку

on-failure[:max-retry] - Перезапускати лише у разі збою

$ docker run -d --restart=always ubuntu echo done

Ця команда запускає контейнер як демон (-d) і завжди перезапускає його після завершення (–restart = always). Вона видає просту команду echo, яка швидко завершується, виходячи із контейнера.

Це можна перевірити командою

doker ps

doker

Важливо, що Docker повторно використовує ідентифікатор контей- нера. Він не змінюється під час перезапуску, і для цього виклику Docker завжди буде лише один запис у таблиці ps.

docker run -d --restart=on-failure:10 ubuntu /bin/false

Ця команда запускає контейнер як демон (-d) і встановлює обмеження на кількість спроб перезапуску (–restart = on-failure: 10), виходячи, якщо вона перевищена. Вона запускає просту команду (/bin/false), яка швидко завершується і неодмінно зазнає невдачі.

Переміщення Docker в інший розділ

ПРОБЛЕМА

Ви хочете перейти туди, де Docker зберігає свої дані.

РІШЕННЯ

Зупиніть та запустіть демон Docker, вказавши нове місце за допомогою прапора -g.

$ dockerd -g /home/dockeruser/mydocker

Також можна відредагувати файл /lib/systemd/system/docker.service та додати цей параметр.

Дозвіл зв’язку між контейнерами

ПРОБЛЕМА

Ви хочете дозволити зв’язок між контейнерами для внутрішніх цілей.

РІШЕННЯ

Використовуйте власні мережі, щоб контейнери могли взаємодіяти один з одним.

Створення мережі.

$ docker network create my_network

Підключення контейнера до мережі.

$ docker network connect my_network blog1

Запуск із явною вказівкою мережі.

$ docker run -it --network my_network ubuntu:16.04 bash

Встановити контейнер з грою під телеграм.

Клонуємо репозиторій.

git clone https://github.com/zdimon/telegram-card-bj
cd telegram-card-bj

Робимо Dockerfile

FROM python:3 as telegramm-card
ENV PYTHONUNBUFFERED 1
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN python3 -m pip install --upgrade pip
RUN pip install -r requirements.txt
CMD python3 start.py

Білдим образ

docker build .

doker

Надаємо йому тег.

docker tag c8ed7da14734 tb-container

Запускаємо контейнер.

doker run -i -t -d  --name tb tb-container