Le conteneur docker de Django n'attrape pas la variable d'environnement ALLOWED_HOSTS dans le pipeline GitLab CI

Aug 19 2020

J'essaie de construire un pipeline GitLab-CI mais Django ne semble pas attraper la variable ALLOWED_HOST passée comme variable d'environnement.

Le projet lui-même est un projet Django exécuté dans un conteneur. Django a besoin d'une valeur ALLOWED_HOSTS et d'une valeur SECRET_KEY dans ses paramètres pour fonctionner. Sur mon environnement de développement ainsi que sur mon serveur de production, les variables sont passées à Django via un fichier env.

Exemple de paramètres Django :

SECRET_KEY = os.environ.get('SECRET_KEY')

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")

Exemple de fichier env :

SECRET_KEY=mydummysecretkey

DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]

Cela fonctionne très bien sur mon dev et mes machines de production.

Mais lorsque j'essaie de l'exécuter dans mon .gitlab-ci.yml, Django ne trouve pas la variable DJANGO_ALLOWED_HOSTS. J'ai toujours cette erreur :

$ docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project

ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
AttributeError: 'NoneType' object has no attribute 'split'
ERROR: Job failed: exit code 1

C'est assez étrange car Django capte bien la variable SECRET_KEY. Comme vous pouvez le voir dans l'extrait de code ci-dessous, j'ai même fait un écho sur la variable qui s'affiche bien.

FYI : Django s'exécute dans un conteneur Docker et le pipeline CI construit l'image (et la pousse vers le registre Gitlab) sur le premier travail afin de le tester sur le deuxième travail (et de le déployer sur le troisième travail).

Voici mon .gitlab-ci.yml :

image: docker:stable

services:
  - docker:19.03.0-dind

variables:
  SECRET_KEY: 'mydummysecretkey_gitlab-ci'
  DJANGO_ALLOWED_HOSTS: 'localhost 127.0.0.1 [::1]'

stages:
  - build
  - test

Build and push stage:
  stage: build
  script:
    - docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
    - docker pull $CI_REGISTRY_IMAGE:latest || true
    - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA ./my_project
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Test stage:
  stage: test
  script:
    - echo $DJANGO_ALLOWED_HOSTS
    - docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
    - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project  # Fails here !
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:latest

Voici la sortie :

$ echo $DJANGO_ALLOWED_HOSTS
localhost 127.0.0.1 [::1]
$ docker login --username $CI_REGISTRY_USER --password "$CI_BUILD_TOKEN" $CI_REGISTRY
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

...

$ docker run --rm $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project
Traceback (most recent call last):
  
...

  File "/usr/src/app/my_project/settings.py", line 32, in <module>
    ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
AttributeError: 'NoneType' object has no attribute 'split'
ERROR: Job failed: exit code 1

Réponses

2 Bravo2bad Aug 20 2020 at 06:35

J'ai eu ma réponse grâce à @Zeitounator

Je citerai simplement son commentaire pour faire simple :

os.environ.getrécupère les variables d'environnement du système en cours d'exécution qui est votre conteneur Docker, et non du système gitlab-ci sous-jacent. Les vars Gitlab CI (comme vos vars shell habituels) ne sont pas automatiquement poussés vers votre conteneur. SECRET_KEYn'émet pas d'avertissement car il est simplement nul. DJANGO_ALLOWED_HOSTSfait parce que vous essayez de le diviser. Vous devez transmettre ces variables env à votre conteneur, soit avec l'option -e docker, soit via un fichier env que vous créez sur place.

Donc, cela fonctionne définitivement:

...

Test stage:
  stage: test
  script:

...

    - docker run --rm -e SECRET_KEY=mydummysecretkey_gitlab-ci -e DJANGO_ALLOWED_HOSTS='localhost 127.0.0.1 [::1]' $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA pytest

...

J'ai fini avec quelque chose comme ça :

docker run --rm -e SECRET_KEY='$SECRET_KEY' -e DJANGO_ALLOWED_HOSTS='$DJANGO_ALLOWED_HOSTS' $CI_COMMIT_SHA pytest