同时这里要注意,数据卷只能映射文件夹而不能映射单一的文件,所以对我们应用的数据库来说,db.sqlite3 文件我们把它挪到了 database 目录下。因此我们要改一下 django 的配置文件中数据库的配置,让它正确地将数据库文件生成在项目根目录下的 database 文件夹下:
DATABASES = { \'default\': { \'ENGINE\': \'django.db.backends.sqlite3\', \'NAME\': os.path.join(BASE_DIR, \'database\', \'db.sqlite3\'), } }env_file: - .envs/.production
容器启动时读取 .envs/.production文件中的内容,将其注入环境变量。
我们创建一下这个文件,把 secret_key 写进去。
DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3注意将这些包含敏感信息的文件加入版本控制工具的忽略列表里,防止一不小心推送到公开仓库供大众观光。
ports: - "8000:8000"
暴露容器内的 8000 端口并且和宿主机的 8000 端口绑定,于是我们就可以通过宿主机的 8000 端口访问容器。
command: /start.sh 容器启动时将执行 start.sh,从而启动 django应用。
nginx 服务容器也类似,只是注意它从数据卷 static 中取静态文件并映射到 nginx 容器内的 /apps/hellodjango_blog_tutorial/static,所以我们在 nginx 的配置中:
location /static { alias /apps/hellodjango_blog_tutorial/static; }这样可以正确代理静态文件。
万事具备,在本地执行一下下面的两条命令来构建容器和启动容器。
docker-compose -f production.yml build docker-compose -f production.yml up此时我们可以通过域名来访问容器内的应用,当然,由于 Nginx 在本地环境的容器内运行,需要修改一下 本地 hosts 文件,让域名解析为本地 ip 即可。
如果本地访问没有问题了,那么就可以直接在服务器上执行上面两条命令以同样的方式启动容器,django 应用就顺利地在服务上部署了。
开发环境既然线上环境都使用 Docker 了,不妨开发环境也一并使用 Docker 进行开发。开发环境的镜像和 docker-compose 文件比线上环境简单一点,因为不用使用 nginx。
开发环境的镜像文件,放到 compose\local 下:
FROM python:3.6-alpine ENV PYTHONUNBUFFERED 1 RUN apk update \ # Pillow dependencies && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev WORKDIR /app RUN pip install pipenv -i https://pypi.douban.com/simple COPY Pipfile /app/Pipfile COPY Pipfile.lock /app/Pipfile.lock RUN pipenv install --system --deploy --ignore-pipfile COPY ./compose/local/start.sh /start.sh RUN sed -i \'s/\r//\' /start.sh RUN chmod +x /start.sh要注意和线上环境不同的是,我们没有把整个代码 copy 到容器里。线上环境代码一般比较稳定,而对于开发环境,由于需要频繁修改和调试代码,如果我们把代码 copy 到容器,那么容器外做的代码修改,容器内部是无法感知的,这样容器内运行的应用就没法同步我们的修改了。所以我们会把代码通过 Docker 的数据卷来管理。
start.sh 不再启动 gunicorn,而是使用 runserver 启动开发服务器。
#!/bin/sh python manage.py migrate python manage.py runserver 0.0.0.0:8000然后创建一个 docker-compose 文件 local.yml(和 production.yml 同级),用于管理开发容器。
version: \'3\' services: djang_blog_tutorial_v2_local: build: context: . dockerfile: ./compose/local/Dockerfile image: django_blog_tutorial_v2_local container_name: django_blog_tutorial_v2_local working_dir: /app volumes: - .:/app ports: - "8000:8000" command: /start.sh注意我们将整个项目根目录下的文件挂载到了 /app 目录下,这样就能容器内就能实时反映代码的修改了。
线上部署如果容器在本地运行没有问题了,线上环境的容器运行也没有问题,因为理论上,我们在线上服务器也会构建和本地测试用的容器一模一样的环境,所以几乎可以肯定,只要我们服务器有 Docker,那么我们的应用就可以成功运行。
首先在服务安装 Docker,安装方式因系统而异,方式非常简单,我们以 CentOS 7 为例,其它系统请参考 Docker 的官方文档。
首先安装必要依赖:
$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2然后添加仓库源:
$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo最后安装 Docker:
$ sudo yum install docker-ce docker-ce-cli containerd.io启动 Docker:
$ sudo systemctl start docker(***服务器忽略)设置 Docker 源加速(使用 daocloud 提供的镜像源),否则拉取镜像时会非常慢
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s在 docker 中运行一个 hello world,确认 docker 安装成功:
$ sudo docker run hello-worlddocker 安装成功了,还要安装一下 docker-compose。其实是一个 python 包,我们直接通过 pip 安装就可以了:
$ pip install docker-compose为了避免运行一些 docker 命令时可能产生的权限问题,我们把系统当前用户加入到 docker 组里:
$ sudo usermod -aG docker ${USER}添加组后要重启一下 shell(ssh 连接的话就断开重连)。
万事俱备,只欠东风了!