本文最初发表于船厂博客。
当您构建 Django 和 PostgreSQL 应用程序时,您可能正在考虑希望它检查的几个框:
使用 Docker 和 Docker Compose 可以帮助您的应用程序为开发生命周期的每个阶段(从本地到生产)做好准备。在这篇文章中,我们将介绍使用 Postgres 数据库为 Django 应用程序自定义 Dockerfile 和 Compose 文件的一些基础知识。
TLDR: Shipyard 维护着一个 Django / Postgres 入门应用程序,设置为使用 Docker 和 Docker Compose 构建和运行。在这里分叉。您可以将其用作项目模板或作为现有应用程序的参考。
Django 是一个基于 Python 的开源 Web 框架。它主要用作网络应用程序的后端。 Django 遵循“自带电池”的理念——它配备了路由支持、登录框架、Web 服务器、数据库工具等等。 Django 经常被拿来与 Flask 进行比较,并且几乎在所有方面都得分更高。
您每天都在使用 Django 应用程序。 Spotify、Doordash、Instagram、Eventbrite 和 Pinterest 都拥有 Django - 这充分说明了它的可扩展性和可伸缩性。
使用 Docker 容器运行 Django 应用程序可以解锁多个新用例。它立即改进了您的本地开发工作流程 - 使设置更清晰、更简单。
如果您想云托管您的项目,通常需要将其容器化。 Docker 容器的伟大之处在于它们可以在从本地到生产的每个开发阶段使用。您还可以分发您的 Docker 映像,以便其他人可以立即运行它,而无需任何安装或构建。
至少,如果您在项目中包含 Dockerfile,则可以确保它每次在每个系统上都以相同的方式构建和运行。
我们的 Python 应用程序需要一个包管理器来跟踪、版本控制和安装其依赖项。这有助于我们管理依赖项初始化/更新,而不是单独执行它们,并跨机器保留包版本。
Pip 和 Poetry 都是 Python 流行的依赖管理器,尽管还有很多其他的依赖管理器(例如 uv、Conda、Rye)。
Pip 非常简单。用户可以在requirements.txt文件中列出他们的软件包及其各自的版本,然后运行pip install来设置它们。用户可以通过运行 pip freeze > 来捕获现有的依赖项及其版本。项目根目录中的requirements.txt。
Poetry 是适用于任何规模的应用程序的高性能包管理器,但它的配置比 Pip 稍微简单一些(它使用带有表、元数据和脚本的 TOML 文件)。 Poetry 还使用锁文件 (poetry.lock) 来“锁定”当前版本的依赖项(以及按版本其依赖项)。这样,如果您的项目在特定时间点在特定机器上运行,则该状态将被保留。运行诗歌 init 会提示用户一系列选项来生成 pyproject.toml 文件。
要 Dockerize 您的 Django 应用程序,您将遵循经典的 Dockerfile 结构(设置基本映像、设置工作目录等),然后使用特定于项目的安装说明(可能在自述文件中找到)对其进行修改。
我们可以选择一个轻量级的 Python 镜像作为这个 Dockerfile 的基础。要按标签浏览版本,请查看 Docker Hub 上的 Python 页面。我在这里选择 Alpine,因为它会使我们的图像保持较小:
FROM python:3.8.8-alpine3.13
在这里,我们将定义 Docker 容器内的工作目录。后面提到的所有路径都与此相关。
WORKDIR /srv
在配置 Poetry 之前,我们需要添加一些库:
RUN apk add --update --no-cache \ gcc \ libc-dev \ libffi-dev \ openssl-dev \ bash \ git \ libtool \ m4 \ g++ \ autoconf \ automake \ build-base \ postgresql-dev
接下来,我们将确保使用最新版本的 Pip,然后使用它在我们的容器内安装 Poetry:
RUN pip install --upgrade pip RUN pip install poetry
This app’s dependencies are defined in our pyproject.toml and poetry.lock files. Let’s bring them over to the container’s working directory, and then install from their declarations:
ADD pyproject.toml poetry.lock ./ RUN poetry install
Now, we’ll copy over the rest of the project, and install the Django project itself within the container:
ADD src ./src RUN poetry install
Finally, we’ll run our project’s start command. In this particular app, it’ll be the command that uses Poetry to start the Django development server:
CMD ["poetry", "run", "python", "src/manage.py", "runserver", "0:8080"]
When we combine the snippets from above, we’ll get this Dockerfile:
FROM python:3.8.8-alpine3.13 WORKDIR /srv RUN apk add --update --no-cache \ gcc \ libc-dev \ libffi-dev \ openssl-dev \ bash \ git \ libtool \ m4 \ g++ \ autoconf \ automake \ build-base \ postgresql-dev RUN pip install --upgrade pip RUN pip install poetry ADD pyproject.toml poetry.lock ./ RUN poetry install ADD src ./src RUN poetry install CMD ["poetry", "run", "python", "src/manage.py", "runserver", "0:8080"]
We’re going to split this app into two services: django and postgres. Our django service will be built from our Dockerfile, containing all of our app’s local files.
For this app, we want to build the django service from our single Dockerfile and use the entire root directory as our build context path. We can set our build label accordingly:
django: build: .
We can map port 8080 on our host machine to 8080 within the container. This will also be the port we use to access our Django app — which will soon be live at http://localhost:8080.
ports: - '8080:8080'
Since our Django app is connecting to a database, we want to instruct Compose to spin up our database container (postgres) first. We’ll use the depends_on label to make sure that service is ready and running before our django service starts:
depends_on: - postgres
Since we’ll be sharing files between our host and this container, we can define a bind mount by using the volumes label. To set the volume, we’ll provide a local path, followed by a colon, followed by a path within the container. The ro flag gives the container read-only permissions for these files:
volumes: - './src:/srv/src:ro'
Combining all the options/configurations from above, our django service should look like this:
django: build: . ports: - '8080:8080' depends_on: - postgres volumes: - './src:/srv/src:ro'
Our Django app is configured to connect to a PostgreSQL database. This is defined in our settings.py:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'app', 'USER': 'obscure-user', 'PASSWORD': 'obscure-password', 'HOST': 'postgres', 'PORT': 5432, } }
We can migrate our existing database to its own Docker container to isolate it from the base Django app. First, let’s define a postgres service in our Compose file and pull the latest lightweight Postgres image from Docker Hub:
postgres: image: 'postgres:14.13-alpine3.20'
To configure our PostgreSQL database, we can pass in a few environment variables to set credentials and paths. You may want to consider using a Secrets Manager for this.
environment: - POSTGRES_DB=app - POSTGRES_USER=obscure-user - POSTGRES_PASSWORD=obscure-password - PGDATA=/var/lib/postgresql/data/pgdata
We can expose our container port by setting it to the default Postgres port: 5432. For this service, we’re only specifying a single port, which means that the host port will be randomized. This avoids collisions if you’re running multiple Postgres instances.
ports: - '5432'
In our postgres definition, we can add a named volume. This is different from the bind mount that we created for the django service. This will persist our data after the Postgres container spins down.
volumes: - 'postgres:/var/lib/postgresql/data'
Outside of the service definitions and at the bottom of the Compose file, we’ll declare the named postgres volume again. By doing so, we can reference it from our other services if needed.
volumes: postgres:
And here’s the resulting PostgreSQL definition in our Compose file:
postgres: image: 'postgres:14.13-alpine3.20' environment: - POSTGRES_DB=app - POSTGRES_USER=obscure-user - POSTGRES_PASSWORD=obscure-password - PGDATA=/var/lib/postgresql/data/pgdata ports: - '5432' volumes: - 'postgres:/var/lib/postgresql/data' volumes: postgres:
We can get our app production-ready by deploying it in a Shipyard application — this means we’ll get an ephemeral environment for our base branch, as well as environments for every PR we open.
Shipyard transpiles Compose files to Kubernetes manifests, so we’ll add some labels to make it Kubernetes-compatible.
Under our django service, we can add two custom Shipyard labels:
labels: shipyard.init: 'poetry run python src/manage.py migrate' shipyard.route: '/'
Next, you can go to your Shipyard dashboard. If you haven’t already, sign up for a 30-day free trial.
Click the + Application button, then select your repo, services, and import your env vars.
Once it finishes building, you can click the green Visit button to access your short-lived ephemeral environment. What comes next?
Now you have a fully containerized Django app with a database! You can run it locally with Docker Compose, preview and test it in an ephemeral environment, and iterate until it’s production-ready.
Want to Dockerize a Yarn app next? Check out our guide!
以上是如何:使用 Docker 将 Django 和 Postgres 应用程序容器化的详细内容。更多信息请关注PHP中文网其他相关文章!