Я новичок в docker swarm и могу развертывать свои службы на различных узлах, однако переменные среды, которые экспортируются из сценария dockerfile ENTRYPOINT
, не устанавливаются для задач, развернутых в кластере docker swarm.
Настройка
- докер версии 18.09.1, сборка 4c52b90
- docker-compose версии 1.23.2, сборка 1110ad01
- Джанго 2.1.5
- ПосгресSQL 10
Пытаясь выполнить одноразовую команду внутри задачи django, используя docker exec -t CONTAINER_ID sh
для входа в контейнер, а затем выполняя python manage.py migrate
, я получаю следующую ошибку:
Ошибка
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "manage.py", line 38, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 211, in fetch_command
settings.INSTALLED_APPS
File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 57, in __getattr__
self._setup(name)
File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 44, in _setup
self._wrapped = Settings(settings_module)
File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 107, in __init__
mod = importlib.import_module(self.SETTINGS_MODULE)
File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/app/config/settings/production.py", line 15, in <module>
DATABASES['default'] = env.db('DATABASE_URL') # noqa F405
File "/usr/local/lib/python3.6/site-packages/environ/environ.py", line 202, in db_url
return self.db_url_config(self.get_value(var, default=default), engine=engine)
File "/usr/local/lib/python3.6/site-packages/environ/environ.py", line 275, in get_value
raise ImproperlyConfigured(error_msg)
django.core.exceptions.ImproperlyConfigured: Set the DATABASE_URL environment variable
Итак, DATABASE_URL
не задано как переменная среды внутри моего контейнера докеров. Как указывалось ранее, это экспортируется из сценария ENTRYPOINT
, который вызывается в файле докеров.
Файл Docker
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN apk update \
# psycopg2 dependencies
&& apk add --virtual build-deps gcc python3-dev g++ musl-dev \
&& apk add postgresql-dev \
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
# CFFI dependencies
&& apk add libffi-dev py-cffi \
# Translations dependencies
&& apk add gettext \
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
# Requirements are installed here to ensure they will be cached.
COPY ./requirements /requirements
RUN pip install -r /requirements/production.txt \
&& rm -rf /requirements
COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r//' /entrypoint
RUN chmod +x /entrypoint
RUN chown django /entrypoint
COPY ./compose/production/django/start /start
RUN sed -i 's/\r//' /start
RUN chmod +x /start
RUN chown django /start
COPY ./compose/production/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r//' /start-celeryworker
RUN chmod +x /start-celeryworker
RUN chown django /start-celeryworker
COPY ./compose/production/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r//' /start-celerybeat
RUN chmod +x /start-celerybeat
RUN chown django /start-celerybeat
COPY ./compose/production/django/celery/flower/start /start-flower
RUN sed -i 's/\r//' /start-flower
RUN chmod +x /start-flower
COPY . /app
RUN chown -R django /app
USER django
WORKDIR /app
ENTRYPOINT ["/entrypoint"]
Скрипт ENTRYPOINT
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
# N.B. If only .env files supported variable expansion...
export CELERY_BROKER_URL="${REDIS_URL}"
if [ -z "${POSTGRES_USER}" ]; then
base_postgres_image_default_user='postgres'
export POSTGRES_USER="${base_postgres_image_default_user}"
fi
export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
postgres_ready() {
python << END
import sys
import psycopg2
try:
psycopg2.connect(
dbname="${POSTGRES_DB}",
user="${POSTGRES_USER}",
password="${POSTGRES_PASSWORD}",
host="${POSTGRES_HOST}",
port="${POSTGRES_PORT}",
)
except psycopg2.OperationalError:
sys.exit(-1)
sys.exit(0)
END
}
until postgres_ready; do
>&2 echo 'Waiting for PostgreSQL to become available...'
sleep 1
done
>&2 echo 'PostgreSQL is available'
exec "$@"
Это было взято из проекта django-cookie-cutter от pydanny. Все работает с использованием обычной установки без роя: docker-compose -f production.yml build
и docker-compose -f production.yml up
для развертывания в производственной среде с одним экземпляром.
Наконец, вот как выглядит мой файл docker-compose для роя:
Docker-compose.yml
version: '3.6'
volumes:
production_postgres_data: {}
production_postgres_data_backups: {}
production_caddy: {}
node-modules:
networks:
webnet:
driver: overlay
attachable: true
services:
django: &django
image: registry:image
depends_on:
- postgres
- redis
env_file:
- PATH to .env
command: /start
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
networks:
- webnet
postgres:
image: registry:image
volumes:
- production_postgres_data:/var/lib/postgresql/data
- production_postgres_data_backups:/backups
env_file:
- PATH to .env
deploy:
restart_policy:
condition: on-failure
delay: 5s
placement:
constraints:
- node.role == manager
networks:
- webnet
frontend:
image: registry:image
command: /start
volumes:
- node-modules:/app/node_modules
ports:
- "3000:3000"
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
networks:
- webnet
caddy:
image: registry:image
depends_on:
- django
- frontend
volumes:
- production_caddy:/root/.caddy
env_file:
- PATH to .env
ports:
- "0.0.0.0:80:80"
- "0.0.0.0:443:443"
deploy:
placement:
constraints:
- node.role == manager
networks:
- webnet
redis:
image: redis:3.2
deploy:
mode: replicated
replicas: 2
networks:
- webnet
Я не уверен, почему экспорт переменных среды из сценария точки входа не устанавливается, когда задачи развертываются на узлах с использованием docker stack deploy --with-registry-auth -c production.yml my_swarm
.
Любая помощь будет оценена по этому или альтернативному решению для установки переменных env. Я не смог найти документацию, которая связывает сценарии точки входа dockerfile с задачами/службами docker swarm.
РЕДАКТИРОВАТЬ:
Я предполагаю, что мне нужно каким-то образом использовать https://docs.docker.com/engine/swarm/secrets/, но хотелось бы сохранить скрипт точки входа.
РЕДАКТИРОВАТЬ 2: Нашел ресурс, нужно адаптировать мой процесс. https://docs.docker.com/engine/swarm/secrets/#build-support-for-docker-secrets-into-your-images
РЕДАКТИРОВАТЬ 3: После дополнительной проверки все остальные переменные среды, кроме тех, которые указаны в сценарии точки входа, переносятся на каждую задачу. Я смог войти в контейнер django, используя docker exec
, и выполнить те же команды для создания DATABASE_URL
, а также CELERY_BROKER_URL
, как показано в сценарии. Однако до сих пор не известно, почему сценарии точки входа нельзя использовать для создания переменных среды.
docker exec
, посколькуdocker exec
создает новую оболочку, которая не является дочерней для вашей точки входа. - person BMitch   schedule 12.02.2019docker exec
для выполнения одноразовых команд, и я должен установить их снова для этого экземпляра. - person Dan R   schedule 12.02.2019