Початок роботи з Doker.
Основи роботи з Linux. -> Django и PostgreSQL с Doker.
Джаного та база даних з Docker.
Створюємо новий проект.
Файл залежностей requirements.txt
Django
psycopg2
Встановлення ВО та залежностей.
Старт проекту та сервера.
В даному випадку ми не застосовували міграцію і базу даних не було створено.
Тепер завдання полягає в тому, щоб не використовувати папку 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.
і спостерігаємо процес
Бачимо, що просить оновити інсталятор pip.
Додамо команду поновлення як просить.
...
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
Тепер нам потрібно запустити кілька команд всередині контейнера, щоб підняти веб-сервер з джанго проектом.
Також нам необхідно зробити посилання всередині контейнера на наш каталог із проектом зовні.
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
Основи роботи з Linux. -> Nginx с Doker.
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
Основи роботи з Linux. -> Flask с Doker.
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) називався робітник, який переносив товари на судна та назад, коли ті стояли в портах.
Там були ящики та вантажі різних розмірів та форм, і досвідчені докери цінувалися за те, що вони спроможні вручну помістити товари на кораблі економічно ефективним способом.
Найняти людей для переміщення цих вантажів було недешево, але альтернативи не було.
Це має бути знайоме всім, хто працює у сфері програмного забезпечення.
Багато часу та інтелектуальної енергії витрачається на перенесення програмного забезпечення на різні системи та сервери.
На рис показано, як можна заощадити час та гроші за допомогою 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
Ключові концепції та команди.
Перш ніж запускати команди Docker, найкраще розібратися з поняттями образів, контейнерів та шарів. Коротко кажучи, контейнери запускають системи, визначені образами. Ці образи складаються з одного або декількох шарів (або наборів відмінностей) плюс деякі метадані Docker.
Основна функція Docker – створювати, відправляти та запускати програмне забезпечення у будь-якому місці, де є Docker.
Для кінцевого користувача Docker це програма з командним рядком, яку вони запускають.
docker build Зібрати образ Docker
docker run Запустити образ Docker як контейнер
docker commit Зберегти контейнер Docker як образ
docker tag Присвоїти тег образу Docker
Один із способів поглянути на образи та контейнери – це розглядати їх як програми та процеси. Так само процес може розглядатися як «додаток, що виконується», контейнер Docker може розглядатися як образ, що виконується Docker.
Якщо ви знайомі з принципами об’єктно-орієнтованого програмування, ще один спосіб поглянути на образи та контейнери – це розглядати образи як класи, а контейнери – як об’єкти.
Контейнери запускають один процес під час запуску. Коли процес завершується, контейнер зупиняється.
Наприклад, з одного образу можна запустити 3 контейнери:
-
django
-
mysql
-
nginx
Способи створення образів.
Їх є кілька.
- Запустити контейнер у командному рядку, вказавши його параметри у команді docker run. Потім можна перенести контейнер образ за допомогою docker commit.
Підійде якщо ви хочете перевірити, чи працює ваш просес установки.
- Виконати збірку з відомого базового образу, вказавши її в Dockerfile.
Dockerfile – це текстовий файл, який містить серію команд.
Основні команди.
FROM
COPY
ADD
RUN
ENTRYPOINT [“
CMD [““, …] : Визначення параметрів команди запуску, враховуючи, що за дефолтом /bin/sh -c, ми можемо до нього додати параметри через CMD.
WORKDIR
Файл Dockerfile починається з базового образу за допомогою команди FROM. У цьому прикладі використовується образ Node.js, тому у вас є доступ до двійкових файлів Node.js. Офіційний образ Node.js називається node.
git вже встановлений у базовому образі, але це не стосується всіх образів.
WORKDIR - не тільки змінює директорію, але й визначає, в якому каталозі ви будете перебувати при запуску програми.
EXPOSE - повідомляє Docker, що контейнери із зібраного образу повинні прослуховувати цей порт.
Как видим Dockerfile – це проста послідовність обмеженого набору команд, що виконуються у строгому порядку.
Тут команда RUN впливає на файлову систему, перевіряючи та встановлюючи програми, а команди EXPOSE, CMD та WORKDIR – на метадані образи.
Складання образу.
Після закінчення зборки нам видадуть остаточний ідентифікатор образу, готовий до присвоєння тега.
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 допомагають подолати велику проблему, яка виникає, коли ви використовуєте контейнери в широкому масштабі.
Уявіть собі, що станеться, якщо ви запустите сотні або навіть тисячі програм, і кожній із них знадобиться копія файлів для зберігання в будь-якому місці.
Як ви можете уявити, дисковий простір закінчиться досить швидко!
За промовчанням Docker внутрішньо використовує механізм копіювання під час запису, щоб зменшити обсяг потрібного дискового простору.
Стисло суть методу.
Ідея підходу copy-on-write полягає в тому, що при читанні області даних використовується спільна копія, у разі зміни даних створюється нова копія.
При створенні образу Doker створює шари файлової системи та їх використовує під час створення нових образів. Наприклад, якщо два образи використовують одну ОС Ubuntu, то вона не буде скопійована в обидва, а вони будуть використовувати один і той же шар, що містить цю операційну систему.
Архітектура Docker
Виходячи з малюнка видно, що докер-образи в реєстрі ми можемо зберігати як на своєму сервері, так і на офіційному сайті 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
Запускаємо на сокеті.
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, як показано у наступному лістингу.
Зупинка контейнера.
$ 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
Важливо, що 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 .
Надаємо йому тег.
docker tag c8ed7da14734 tb-container
Запускаємо контейнер.
doker run -i -t -d --name tb tb-container