线上环境使用 Nginx,同样来编排 Nginx 的镜像,这个镜像文件放到 compose\production\nginx 目录下:
FROM nginx:1.17.1 # 替换为国内源 RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak COPY ./compose/production/nginx/sources.list /etc/apt/ RUN apt-get update && apt-get install -y --allow-unauthenticated certbot python-certbot-nginx RUN rm /etc/nginx/conf.d/default.conf COPY ./compose/production/nginx/HelloDjango-blog-tutorial.conf /etc/nginx/conf.d/HelloDjango-blog-tutorial.conf这个镜像基于 nginx:1.17.1 基础镜像构建,然后我们更新系统并安装 certbot 用于配置 https 证书。由于要安装大量依赖, nginx:1.17.1 镜像基于 ubuntu,所以安装会比较慢,我们将软件源替换为国内源,这样稍微提高一下安装速度。
最后就是把应用的 nginx 配置复制到容器中 nginx 的 conf.d 目录下。里面的内容和直接在系统中配置 nginx 是一样的。
upstream hellodjango_blog_tutorial { server hellodjango_blog_tutorial:8000; } server { server_name hellodjango-blog-tutorial-demo.zmrenwu.com; location /static { alias /apps/hellodjango_blog_tutorial/static; } location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass ; } listen 80; }相比之前直接在宿主机配置 Nginx,这里使用了 Nginx 的 upstream 模块,实际上就是做一个请求转发。Nginx 将所有请求转发给上游 hellodjango_blog_tutorial 模块处理,而 hellodjango_blog_tutorial 这个模块的服务实际就是运行 django 应用的容器 hellodjango_blog_tutorial(接下来会运行这个容器)。
镜像编排完毕,接下来就可以通过镜像构建容器并运行容器了。但是先等一等,我们有两个镜像,一个是 django 应用的,一个是 Nginx 的,这意味着我们需要构建 2 次容器,并且启动容器 2 次,这会比较麻烦。有没有办法一次构建,一条命令运行呢?答案就是使用 docker-compose。
docker-compose 将各个容器的镜像,以及构建和运行容器镜像时的参数等编写在一个 ymal 文件里。这样我们只需要一条 build 命令就可以构建多个容器,使用一条命令 up 就可以启动多个容器。
我们在项目根目录建一个 production.yml 文件来编排 django 容器和 nginx 容器。
version: \'3\' volumes: static: database: services: hellodjango_blog_tutorial: build: context: . dockerfile: compose/production/django/Dockerfile image: hellodjango_blog_tutorial container_name: hellodjango_blog_tutorial working_dir: /app volumes: - database:/app/database - static:/app/static env_file: - .envs/.production ports: - "8000:8000" command: /start.sh nginx: build: context: . dockerfile: compose/production/nginx/Dockerfile image: hellodjango_blog_tutorial_nginx container_name: hellodjango_blog_tutorial_nginx volumes: - static:/apps/hellodjango_blog_tutorial/static ports: - "80:80" - "443:443"version: \'3\' 声明 docker-compose 为第三代版本的语法
volumes: static: database:声明了 2 个命名数据卷,分别为 static 和 database。数据卷是用来干嘛的呢?由于 docker 容器是一个隔离环境,一旦容器被删除,容器内的文件就会一并删除。试想,如果我们启动了博客应用的容器并运行,一段时间后,容器中的数据库就会产生数据。后来我们更新了代码或者修改了容器的镜像,这个时候就要删除旧容器,然后重新构建新的容器并运行,那么旧容器中的数据库就会连同容器一并删除,我们辛苦写的博客文章付之一炬。
所以我们使用 docker 的数据卷来管理需要持久存储的数据,只要数据被 docker 的数据卷管理起来了,那么新的容器启动时,就可以从数据卷取数据,从而恢复被删除容器里的数据。
我们有 2 个数据需要被数据卷管理,一个是数据库文件,一个是应用的静态文件。数据库文件容易理解,那么为什么静态文件也要数据卷管理呢?启动新的容器后使用 python manage.py collectstatic 命令重新收集不就好了?
答案是不行,数据卷不仅有持久保存数据的功能,还有跨容器共享文件的功能。要知道,容器不仅和宿主机隔离,而且容器之间也是互相隔离的。Nginx 运行于独立容器,那么它处理的静态文件从哪里来呢?应用的静态文件存放于应用容器,Nginx 容器是访问不到的,所以这些文件也通过数据卷管理,nginx 容器从数据卷中取静态文件映射到自己的容器内部。
接下来定义了 2 个 services,一个是应用服务 hellodjango_blog_tutorial,一个是 nginx 服务。
build: context: . dockerfile: compose/production/django/Dockerfile告诉 docker-compose,构建容器是基于当前目录(yml 文件所在的目录),且使用的镜像是 dockerfile 指定路径下的镜像文件。
image 和 container_name 分别给构建的镜像和容器取个名字。
working_dir 指定工作目录。
volumes: - database:/app/database - static:/app/static