在不输入密码的情况下在 docker 容器中创建 django 超级用户

Create django super user in a docker container without inputting password

我正在尝试在带有 fabric 的 django docker 容器中创建超级用户。

要在 django 中创建超级用户,我需要 运行 在 django 交互模式下:

./manage.py createsuperuser

而且因为我想在 fabric 脚本中实现 运行,所以我发现 this 命令可以避免输入密码

echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | ./manage.py shell

然后我将它与 "docker exec" 放在一起 运行 在我的 django 容器中

docker exec container_django echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | ./manage.py shell

问题出在linux管道,管道(|)左边的所有内容(包括docker exec)右边的(./manage.py shell)

这不仅是困难的部分,考虑将所有这些垃圾放入结构中 运行,这意味着他们需要在两端引用。它会使整个事情变得非常丑陋。

fabric run:
run("docker exec container_django {command to create django super user}")

我仍在努力研究如何至少让垃圾在织物中发挥作用 运行,但我不知道该怎么做。

可能最简单的方法是将 Python 脚本放在一起为您创建 Django 超级用户,而不是尝试通过 manage.py shell 提供所有这些命令。你能把你的命令放在一个 .py 文件中吗,比方说 yourfile.py:

#!/usr/bin/env python

from django.contrib.auth.models import User
User.objects.create_superuser('admin', 'admin@example.com', 'pass')

然后,在 chmod +x yourfile.py:

fabric run:
run("docker exec container_django yourfile.py")

根据您的设置,您可能需要确保为 运行() 命令正确设置 DJANGO_SETTINGS_MODULE 环境变量。

我建议添加一个新的管理命令,如果不存在用户,它将自动创建一个超级用户。

参见我在 https://github.com/dkarchmer/aws-eb-docker-django 创建的小示例。特别是,看看我是如何运行 python manage.py initadmin 的:

class Command(BaseCommand):

    def handle(self, *args, **options):
        if Account.objects.count() == 0:
            for user in settings.ADMINS:
                username = user[0].replace(' ', '')
                email = user[1]
                password = 'admin'
                print('Creating account for %s (%s)' % (username, email))
                admin = Account.objects.create_superuser(email=email, username=username, password=password)
                admin.is_active = True
                admin.is_admin = True
                admin.save()
        else:
            print('Admin accounts can only be initialized if no Accounts exist')

(参见 Authentication/management/commands)。

您可以看到 Dockerfile 然后如何运行 CMD 到 runserver.sh,它基本上运行

python manage.py migrate --noinput
python manage.py initadmin
python manage.py runserver 0.0.0.0:8080

显然,这假设管理员在服务器启动后立即更改密码。这对你来说可能不够好。

免责声明:

将密码明文存储在 Docker 文件中是不安全的,因为可以随时从图像中提取密码,并且 Docker 文件通常会提交版本控制。但是,这个答案与密码安全无关,而是与 createsuperuser 命令自动化有关;如果您正在寻找存储超级用户密码的正确方法,请查看这个 SO 问题:Docker and secure passwords .


我通过评估 Docker 文件中的 python 代码行来处理这个问题。

ENV DJANGO_DB_NAME=default
ENV DJANGO_SU_NAME=admin
ENV DJANGO_SU_EMAIL=admin@my.company
ENV DJANGO_SU_PASSWORD=mypass

RUN python -c "import django; django.setup(); \
   from django.contrib.auth.management.commands.createsuperuser import get_user_model; \
   get_user_model()._default_manager.db_manager('$DJANGO_DB_NAME').create_superuser( \
   username='$DJANGO_SU_NAME', \
   email='$DJANGO_SU_EMAIL', \
   password='$DJANGO_SU_PASSWORD')"

请注意,这与调用

不同
User.objects.create_superuser('admin', 'admin@example.com', 'pass')

as django.contrib.auth.get_user_model 如果你应该有的话,custom user model 会很好地工作(这很常见),而 User.objects.create 你只创建一个标准的用户实体,忽略任何自定义用户模型。

此外,它与 django 的 createsuperuser 命令 does under the hood 的调用相同,所以这样做应该很安全。

我拿了,稍微改了一下

我需要在构建步骤之后创建超级用户。所以我把它放在主管脚本中。这意味着它会在每次 i 运行 容器时执行。所以我添加了一个简单的 if / else 控件来检查是否已经创建了超级用户。这减少了执行时间。我们还需要设置 DJANGO_SETTINGS_MODULE 环境变量。

python -c "import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'project_name.settings'
import django
django.setup()
from django.contrib.auth.management.commands.createsuperuser import get_user_model
if get_user_model().objects.filter(username='$DJANGO_SUPERUSER_USERNAME'): 
    print 'Super user already exists. SKIPPING...'
else:
    print 'Creating super user...'
    get_user_model()._default_manager.db_manager('$DJANGO_DB_NAME').create_superuser(username='$DJANGO_SUPERUSER_USERNAME', email='$DJANGO_SUPERUSER_EMAIL', password='$DJANGO_SUPERUSER_PASSWORD')
    print 'Super user created...'"

获取容器 ID 和 运行 命令。

docker exec -it container_id python manage.py createsuperuser

我建议 运行 Data Migration,这样当您通过 docker-compose up 启动 Docker 服务(例如应用程序和数据库)时,您可以准确地执行所有迁移曾经 docker-compose exec web python code/manage.py migrate

因此您的迁移将如下所示(假设您将凭据等存储在环境变量中)

import os
from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        ('<your_app>', '<previous_migration>'),
    ]

    def generate_superuser(apps, schema_editor):
        from django.contrib.auth.models import User

        DJANGO_DB_NAME = os.environ.get('DJANGO_DB_NAME', "default")
        DJANGO_SU_NAME = os.environ.get('DJANGO_SU_NAME')
        DJANGO_SU_EMAIL = os.environ.get('DJANGO_SU_EMAIL')
        DJANGO_SU_PASSWORD = os.environ.get('DJANGO_SU_PASSWORD')

        superuser = User.objects.create_superuser(
            username=DJANGO_SU_NAME,
            email=DJANGO_SU_EMAIL,
            password=DJANGO_SU_PASSWORD)

        superuser.save()

    operations = [
        migrations.RunPython(generate_superuser),
    ]

这允许您使用构建的容器对数据库执行,无论它是同一容器中的本地数据库还是单独的服务。而且并不是每次重建容器时都这样做,而是只有在需要迁移时才这样做。

None 个答案在我的项目中有效。 这有效:

docker exec web ./manage.py shell -c "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('your_user', 'your_password')"

我在使用 compose 时使用了这个命令

docker-compose run <web> python manage.py createsuperuser

其中 <web> 是 docker 服务的名称(在 docker-compose.yml 中) https://docs.docker.com/compose/reference/run/

当 运行 使用 Dockerfile

docker exec -it <container_id> python manage.py createsuperuser

使用环境变量和非交互模式。所以你在你的 env 文件中添加这样的东西。

DJANGO_SUPERUSER_PASSWORD=**********
DJANGO_SUPERUSER_EMAIL=example@example.com
DJANGO_SUPERUSER_USERNAME=admin

然后,在您的 docker 入口点文件中,添加以下命令:

python manage.py makemigrations
python manage.py migrate
python manage.py createcachetable

if [ "$DJANGO_SUPERUSER_USERNAME" ]
then
    python manage.py createsuperuser \
        --noinput \
        --username $DJANGO_SUPERUSER_USERNAME \
        --email $DJANGO_SUPERUSER_USERNAME
fi

$@

请注意,无需输入密码,因为 Django 的 createsuperuser 脚本在非交互模式下默认从 DJANGO_SUPERUSER_PASSWORD 获取密码。

这将运行迁移并在使用环境变量启动容器时根据需要创建管理员用户。

创建文件 Makefile

.ONESHELL:
reset-superuser: SHELL := python
reset-superuser:
    import os
    import django
    from django.contrib.auth import get_user_model

    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.develop")
    django.setup()

    User = get_user_model()
    user = User.objects.filter(is_superuser=True).first()

    if user:
        user.set_password("admin")
        user.save()
    else:
        user = User.objects.create_superuser(
            username="josuedjh",
            first_name="Josue djh",
            password="admin",
        )

    print(f"Superuser {user.username!r} with password `admin`")

运行 命令:

make reset-superuser

我使用decople lib从.env文件中加载了环境变量,并测试了用户名是否存在。

from decouple import config
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def handle(self, *args, **options):
        username = config('DJANGO_SUPERUSER_USERNAME')
        email = config('DJANGO_SUPERUSER_EMAIL')
        password = config('DJANGO_SUPERUSER_PASSWORD')

        if not User.objects.filter(username=username).exists():
            print('Creating account for %s (%s)' % (username, email))
            admin = User.objects.create_superuser(
                email=email, username=username, password=password)
        else:
            print('Admin account has already been initialized.')

所以我这样做:

  source .env
  python manage.py initadmin

我的 .env 文件有:

DJANGO_SUPERUSER_USERNAME=admin
DJANGO_SUPERUSER_EMAIL=admin@admin.com
DJANGO_SUPERUSER_PASSWORD=mypass

如果您要 运行在容器中安装 Django,干净优雅的方法是不要将任何额外的自定义代码或命令放入代码库。而是使用 bash 脚本来 运行 任何所需的配置(例如创建超级用户)。通过这种方式,您可以更好地管理和自动化您的配置,并保持代码库清洁和跨环境可重用。 输入你的 docker-compose.yml

command: >
  bash -c '.. 
  && source create_superuser_prod.sh 
  && ..'

放入create_superuser_prod.sh

echo "from django.contrib.auth.models import User; User.objects.create_superuser($PROD_USER,$PROD_USER_EMAIL,$PROD_USER_PASS)" | python manage.py shell