Образовательный проект «SnakeProject» Михаила Козлова

Навигация

⇒ FreeBSD and Nix ⇐

CISCO

Voice(Asterisk\Cisco)

Microsoft

Powershell

Python

SQL\T-SQL

Общая

WEB Разработка

ORACLE SQL \ JAVA

Мото

Стрельба, пневматика, оружие

Саморазвитие и психология


Быстрое прототипирование с Flask, uWSGI, NGINX, и Docker на OpenShift


 

Быстрое прототипирование с Flask, uWSGI, NGINX, и Docker на OpenShift


Перевод по мотивам статьи:
https://towardsdatascience.com/how-to-do-rapid-prototyping-with-flask-uwsgi-nginx-and-docker-on-openshift-f0ef144033cb


Код из git:
https://github.com/szelenka/openshift-prototype


Проект на докерхабе:
https://hub.docker.com/r/szelenka/prototype/

 

Создадим директорию для проекта:
mkdir -p /data/webapp


План проекта:

cd /data/webapp

git clone https://github.com/szelenka/openshift-prototype.git .


tree .
.
├── deployment
│   ├── docker-entrypoint.sh
│   ├── Dockerfile
│   ├── nginx.conf
│   ├── supervisord.conf
│   └── uwsgi.ini
├── deploy.sh
├── README.md
└── src
    ├── __init__.py
    ├── static
    │   └── index.html
    └── wsgi.py


Приведенная выше структура помещает всю информацию о контейнере в папку deployment
Весь код и ресурсы Python попадают в папку src в виде псевдомодуля
Подумайте о своем коде данных, живущем в src и определяющем конечные точки в файле wsgi.py


Установите фласк, если нету в ос:
yum -y install python-flask


Проверяем приложение в режиме отладки:
python ./src/wsgi.py
 * Running on http://0.0.0.0:8080/
 * Restarting with reloader


http://10.106.65.42:8080/
Simple response from Flask running inside uWSGI, which is running within nGINX, which is hosted inside a Docker image!

 

Для этого поста мы хотим запустить наше приложение Flask внутри NGINX и uWSGI на OpenShift
Необходимо сначала настроить uWSGI, указать, где он может найти приложение Flask
Это делается в файле конфигурации ./deployment/uwsgi.ini

Конфиг uwsgi:
cat ./deployment/uwsgi.ini
[uwsgi]
chdir=/opt/repo/src
chdir2=/opt/repo/src
master = true

module=wsgi
callable=app
buffer-size=65535
lazy=true

socket = /run/uwsgi.sock
#chown-socket = nginx:nginx
#chmod-socket = 664
cheaper = 2
processes = 16


Основными вариантами, на которые следует обратить внимание, являются module и callable
Эти два параметра указывают службе uWSGI, где искать код Python для выполнения
В нашем случае мы просим его искать в папке /opt/repo/src файл wsgi.py и переменную app в этом файле
(которая является нашей главной вызываемой переменной Flask)

Явно указываем, где находится файл сокета этой службы, который нужно будет согласовать с конфигурацией NGINX

 


Конфигурация NGINX

Затем нам нужно сообщить NGINX, где он может найти файл сокета uWSGI
Когда новые запросы поступают на прослушиваемый порт, он знает, как соответствующим образом направить запросы
Это делается в файле ./deployment/nginx.conf

Конфиг nginx:
cat ./deployment/nginx.conf
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    tcp_nopush on;

    client_body_temp_path /spool/nginx/client_temp 1 2;
    fastcgi_temp_path /spool/nginx/fastcgi_temp 1 2;
    proxy_temp_path /spool/nginx/proxy_temp 1 2;
    scgi_temp_path /spool/nginx/scgi_temp 1 2;
    uwsgi_temp_path /spool/nginx/uwsgi_temp 1 2;

    server {
        listen 8080;
        server_name localhost;

        access_log /var/log/nginx/access.log;

        location / {
            try_files $uri @app;
        }
        location @app {
            include uwsgi_params;
            uwsgi_pass unix:///run/uwsgi.sock;
        }
        location /static {
            alias /opt/repo/src/static;
            expires 1d;
        }
    }
}


Определяем, где служба NGINX должна пытаться создать какие-либо журналы, временные файлы, какие порты прослушивать
Поскольку OpenShift будет запускать этот образ как произвольный пользователь, мы не можем использовать любые номера портов ниже 1024
(т.е. привилегированные порты, такие как стандартный HTTP 80 или HTTPS 443)
Поэтому назначим службе прослушивать порт 8080
Затем в рамках маршрутизации местоположения мы говорим NGINX направлять все запросы к сокету uWSGI и приложению Python (то есть @app)
За исключением любых статических файлов, которые должны идти непосредственно в эту папку на диске

 


Супервизор Конфиг

Последнее, что нам нужно настроить, - это способ заставить все это работать в одном образе
Лучшие практики Docker настоятельно рекомендуют одно приложение для каждого образа
В нашем случае нам нужен uWSGI для запуска нашего кода Python и NGINX для маршрутизации в uWSGI
Поэтому мы будем использовать хитрость запуска Supervisord для обработки нескольких одновременных сервисов
Это делается в файле ./deployment/supervisord.conf


Конфиг supervisord:
cat ./deployment/supervisord.conf
[unix_http_server]
file=/run/supervisor.sock
chmod=0770

[supervisord]
nodaemon=true
pidfile=/run/pid/supervisord.pid
logfile=/var/log/supervisor/supervisord.log
childlogdir=/var/log/supervisor
logfile_maxbytes=50MB
logfile_backups=1

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///run/supervisor.sock

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;" -c /etc/nginx/nginx.conf
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:uwsgi]
command=/usr/local/bin/uwsgi --ini /etc/uwsgi/apps-enabled/uwsgi.ini
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0


Указываем, какие команды выполнять для каждой службы
Расположение файлов конфигурации, которые мы подробно описали ранее
Вы можете запустить supervisord или systemd от root и переключить пользователя для выполнения определенных служб
Однако, с произвольным идентификатором пользователя в OpenShift мы должны разрешить запуск этих служб как любой пользователь в группе root
Вот почему мы не указываем какие-либо пользовательские параметры в файле конфигурации и направляем журналы в /dev/stdout
(что позволит им отображаться в файлах журнала Docker во время работы образа)

 


Docker ENTRYPOINT

Когда файлы конфигурации настроены, нам просто нужно сказать Docker, что выполнять при запуске образа
Использование произвольного идентификатора пользователя в некоторых приложениях Python вносит корректировки в эти планы

Хорошей новостью является то, что есть простой обходной путь
Каждый раз, когда запускается наш образ Docker, нам просто нужно добавить проверку
Убедиться, что произвольный пользователь имеет запись в файле /etc/passwd
Это делается в файле ./deployment/docker-entrypoint.sh

 

Скрипт docker-entrypoint:
cat ./deployment/docker-entrypoint.sh
#!/bin/bash
set -e

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html
# if the running user is an Arbitrary User ID
if ! whoami &> /dev/null; then
  # make sure we have read/write access to /etc/passwd
  if [ -w /etc/passwd ]; then
    # write a line in /etc/passwd for the Arbitrary User ID in the 'root' group
    echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd
  fi
fi

# https://success.docker.com/article/use-a-script-to-initialize-stateful-container-data
if [ "$1" = 'supervisord' ]; then
    exec /usr/bin/supervisord
fi


exec "$@"

 

Для того, чтобы это работало правильно, нужно настроить образ Docker, разрешить всем пользователям доступ на запись в файл /etc/passwd
Как только это будет сделано, мы указываем второе условие, которое нужно отследить
Когда выполнять приложение supervisord в качестве произвольного идентификатора пользователя и направить все журналы в /dev/stdout
(supervisord в свою очередь, выполнит uWSGI и NGINX)

 


Dockerfile

Последний шаг в развертывании - сказать Docker, как создать и настроить образ с помощью файлов конфигурации, которые указали выше
Приятно то, что как только мы сделаем это один раз, сможем повторно использовать структуру/образ для будущих итераций нескольких проектов
Это делается в файле ./deployment/Dockerfile


cat ./deployment/Dockerfile
# Use the standard Nginx image from Docker Hub
FROM nginx

ENV HOME=/opt/repo

# install python, uwsgi, and supervisord
RUN apt-get update && apt-get install -y supervisor uwsgi python python-pip procps vim && \
    /usr/bin/pip install uwsgi==2.0.17 flask==1.0.2

# Source code file
COPY ./src ${HOME}/src

# Copy the configuration file from the current directory and paste
# it inside the container to use it as Nginx's default config.
COPY ./deployment/nginx.conf /etc/nginx/nginx.conf

# setup NGINX config
RUN mkdir -p /spool/nginx /run/pid && \
    chmod -R 777 /var/log/nginx /var/cache/nginx /etc/nginx /var/run /run /run/pid /spool/nginx && \
    chgrp -R 0 /var/log/nginx /var/cache/nginx /etc/nginx /var/run /run /run/pid /spool/nginx && \
    chmod -R g+rwX /var/log/nginx /var/cache/nginx /etc/nginx /var/run /run /run/pid /spool/nginx && \
    rm /etc/nginx/conf.d/default.conf

# Copy the base uWSGI ini file to enable default dynamic uwsgi process number
COPY ./deployment/uwsgi.ini /etc/uwsgi/apps-available/uwsgi.ini
RUN ln -s /etc/uwsgi/apps-available/uwsgi.ini /etc/uwsgi/apps-enabled/uwsgi.ini

COPY ./deployment/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN touch /var/log/supervisor/supervisord.log

EXPOSE 8080:8080

# setup entrypoint
COPY ./deployment/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh

# access to /dev/stdout
# https://github.com/moby/moby/issues/31243#issuecomment-406879017
RUN ln -s /usr/local/bin/docker-entrypoint.sh / && \
    chmod 777 /usr/local/bin/docker-entrypoint.sh && \
    chgrp -R 0 /usr/local/bin/docker-entrypoint.sh && \
    chown -R nginx:root /usr/local/bin/docker-entrypoint.sh

# https://docs.openshift.com/container-platform/3.3/creating_images/guidelines.html
RUN chgrp -R 0 /var/log /var/cache /run/pid /spool/nginx /var/run /run /tmp /etc/uwsgi /etc/nginx && \
    chmod -R g+rwX /var/log /var/cache /run/pid /spool/nginx /var/run /run /tmp /etc/uwsgi /etc/nginx && \
    chown -R nginx:root ${HOME} && \
    chmod -R 777 ${HOME} /etc/passwd

# enter
WORKDIR ${HOME}
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["supervisord"]cat: file: No such file or directory


Этот пост не предназначен для просмотра каждой строки Dockerfile.
Просто знайте, что мы начинаем с официальной сборки NGINX (на которой уже установлен NGINX)
Добавляем несколько пакетов Python через PIP
Явно устанавливаем разрешения для всех папок, к которым NGINX, uWSGI и Supervisord будут касаться во время выполнения
Поэтому произвольный идентификатор пользователя в root группе имеет необходимые разрешения
Наконец, просим образ взглянуть на файл docker-entrypoint.sh, чтоб запускать supervisord для каждого запуска образа по умолчанию

 

Построение Docker image

Чтобы собрать все вышеупомянутые строительные блоки вместе, нам просто нужно выполнить сборку образа Docker


pwd
/data/webapp

docker build -f ./deployment/Dockerfile -t prototype:latest .

Выше примере нам нужно выполнить сборку из корневого каталога, чтобы у контекста сборки был доступ к папкам ./deployment и ./src

 

Тестирование образа Docker как произвольного идентификатора пользователя

Одно дело успешно создать свой образ Docker, другое - заставить работать в OpenShift, работающим под произвольным идентификатором пользователя
Хорошей новостью является то, что мы можем проверить это на нашей локальной машине с флагом пользователя -u

docker run -p 8080:8080 -u 777 prototype:latest


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

Кроме того, мы перенаправляем порт 8080 на нашем локальном компьютере в службу NGINX внутри контейнера
Эт означает, что мы должны иметь возможность открыть веб-браузер на следующих конечных точках:
http://localhost:8080/static/index.html : загрузить статическую HTML-страницу из NGINX
http://localhost:8080/ : загрузить универсальную домашнюю конечную точку из Flask
http://localhost:8080/echo_request : Эхо заголовок запроса из Flask обратно к вызывающей

 


Устранение неполадок с образами Docker

Если вышеперечисленное не работает, нужно отладить, чтоб выяснить, какие разрешения нужны приложению, и соответствующим образом изменить файл Docker

Чтобы отладить образ, вы можете перезаписать команду entrypoint командой:
docker run -it -p 8080:8080 -u 0 prototype:latest /bin/bash

Которая перенаправит вас в интерактивную командную строку bash от имени пользователя root, чтоб могли копаться для устранения неполадок внутри образа
Вам также может потребоваться изменить идентификатор пользователя, используемый в аргументе -u
Используйте CTRL + D или выход для завершения образа

Чтобы проверить выполнение supervisord, в командной строке bash вы можете выполнить следующее, чтоб просмотреть журналы, чтоб определить, в чем проблема
supervisorctl [start|stop|restart] nginx # NGINX service
supervisorctl [start|stop|restart] uwsgi # uWSGI service

Иногда ваше состояние сборки становится грязным с кучей образов, которые вам больше не нужны и занимают место на диске
Чтобы убрать это, вы можете запустить:
docker system prune

 

Развертывание в репозиторие контейнеров

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

Существует несколько способов создания и развертывания образов в OpenShift
Мы не будем вдаваться в конвейеры развертывания в этом посте
Все, что нам нужно сделать, это отправить наш образ в репозиторий контейнеров (например, Docker Hub), затем дать OpenShift команду извлечь и развернуть образ

Сначала нам нужно пройти аутентификацию в нашем репозиторие контейнеров
Где yourhubusername - это ваше имя пользователя в репозиторие контейнеров
youremail@company.com - ваш адрес электронной почты, указанный в репозиторие контейнеров

docker login --username=yourhubusername --email=youremail@example.com


Затем build/tag/push наше образ в этот контейнерный репозиторий
Где yourhubusername - это ваше имя пользователя в репозиторие контейнеров, в котором вы аутентифицировались

docker build -f ./deployment/Dockerfile -t prototype:latest .
docker tag $(docker images | grep ^prototype |awk '{print $3}') yourhubusername/prototype:latest
docker push yourhubusername/prototype:latest


Теперь образ должен быть в вашем репозиторие контейнеров
Если вы используете общедоступный Docker Hub, можете перейти к своим репозиториям по этому URL (после аутентификации) и увидеть свое новый образ:
https://hub.docker.com/

 


Развертывание в OpenShift

Openshift - платформа для разработки и публикации ПО, базируется на платформе оркестрации контейнеров Kubernetes

Теперь давайте скажем OpenShift выполнить развертывание из этого образа
Для этого мы собираемся использовать инструмент OpenShifts CLI
Для начала нам нужно пройти аутентификацию на нашем сервере OpenShift
Просто замените URL своим сервером OpenShift, а <MY_TOKEN> - своим токеном OpenShift

oc login https://my.openshift-servername.com --token=<MY_TOKEN>


Для создания развертывания из CLI нам просто нужно сообщить OpenShift, где найти наш образ Docker
Для получения подробной информации о конфигурации OpenShift посетите страницу:
https://docs.openshift.com/enterprise/3.2/cli_reference/get_started_cli.html


По сути, просто укажите на образ в репозиторие контейнеров, который мы только что создали
oc new-app yourhubusername/prototype


Затем нам нужно указать OpenShift добавить маршрут, чтобы наш веб-трафик мог доходить до нашего образа
Ниже мы говорим, чтобы он направлял трафик, предназначенный для prototype.example.com, для использования службы prototype через порт TCP 8080
Это эффективно говорит OpenShift, как направлять трафик к нашему образу NGINX, который мы только что создали
oc create route edge --service=prototype --hostname=prototype.example.com --port=8080-tcp


Теперь вы должны быть в состоянии перейти к комбинации hostname:port, чтоб увидеть ваше приложение, работающее в OpenShift, от произвольного пользователя

 


Время магической итерации

Теперь, когда мы прошли через всю эту конфигурацию и сборку, мы можем быстро перебрать прототип
Поскольку наш Dockerfile просто скопировал наш код Python из папки ./src, чтобы обновить образ, мы должны убедиться, что новый код находится внутри папки ./src
Проведем локальное тестирование с помощью нашей команды отладки Flask:
python ./src/wsgi.py


После того, как мы довольны новой функциональностью, мы можем создать и отправить изображение с помощью простой команды ./deploy.sh:
bash ./deploy.sh yourhubusername prototype latest


После завершения команды ваш URL в OpenShift выполнит непрерывное обновление службы и представит ваши новые функциональные возможности в прототипе всего за 5 минут

 

Исходный код (Репозиторий)

Пример кода и конфигурации, упомянутых в этом посте, находится на моей странице GitHub здесь
https://github.com/szelenka/openshift-prototype

 


Комментарии пользователей

Эту новость ещё не комментировалиНаписать комментарий
Анонимам нельзя оставоять комментарии, зарегистрируйтесь!

Контакты Группа ВК Сборник материалов по Cisco, Asterisk, Windows Server, Python и Django, SQL и T-SQL, FreeBSD и LinuxКод обмена баннерами Видео к IT статьям на YoutubeВидео на другие темы Смотреть
Мои друзья: Советы, помощь, инструменты для сис.админа, статическая и динамическая маршрутизация, FreeBSD

© Snakeproject.ru создан в 2013 году.
При копировании материала с сайта - оставьте ссылку.

Рейтинг@Mail.ru
Рейтинг@Mail.ru Яндекс.Метрика





Поддержать автора и проект