惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
ThreatConnect
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
H
Help Net Security
T
Threat Research - Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
A
Arctic Wolf
G
Google Developers Blog
量子位
U
Unit 42
I
InfoQ
V
V2EX
F
Fox-IT International blog
P
Privacy & Cybersecurity Law Blog
V
Visual Studio Blog
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏
C
CERT Recently Published Vulnerability Notes
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
SecWiki News
SecWiki News
Know Your Adversary
Know Your Adversary
MyScale Blog
MyScale Blog
宝玉的分享
宝玉的分享
The Hacker News
The Hacker News
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
C
Cisco Blogs
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
Recorded Future
Recorded Future
T
Tenable Blog
W
WeLiveSecurity
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
T
The Blog of Author Tim Ferriss
www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
Docker
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives

追梦人物的博客

0x05:Merkle Tree & Patricia Trie 0x04:ECDSA LeetCode 105 从前序与中序遍历构造二叉树 迭代算法原理 + 完整证明 0x03:Address 0x02:Secp256k1 - 以太坊设计与实现 0x00:专栏开篇 0x01:RLP 编码 - 以太坊设计与实现 Bellman-Ford 算法原理及其在 DeFi 套利中的应用 迪杰斯特拉(Dijkstra)最短路径算法原理、实现与证明 实战:CEX-DEX 稳定币套利监控程序开发 - 追梦人物的博客 CEX-DEX 稳定币套利模型 Uniswap 手续费和协议费机制剖析 - 追梦人物的博客 Uniswap 流动性机制及相关数学原理分析 - 追梦人物的博客 uv 替代 pyenv + pipx + poetry 环境管理实践 Rust 项目从创建到发布 VS Code 调试 Python 比特币跨市场套利的数学模型 ERC-20 相关知识点总结 Django 老项目如何从 SQLite 迁到 PostgreSQL 自动生成接口文档 单元测试 限制接口访问频率 API 版本管理 - HelloDjango - django REST framework 教程 如何在 Windows 下搭建高效的 django 开发环境 拓展Python Markdown - 追梦人物的博客 加缓存为接口提速 基于 drf-haystack 实现文章搜索接口 评论接口 实现分类、标签、归档日期接口 在接口返回Markdown解析后的内容 文章详情接口 分页 使用视图集简化代码 用类视图实现首页 API 实现博客首页文章列表 API - HelloDjango - django REST framework 教程 初始化 RESTful API 风格的博客系统 django-rest-framework 是什么鬼? - HelloDjango - django REST framework 教程 结束 or 开始? Coverage.py 统计测试覆盖率 单元测试:测试评论应用 单元测试:测试 blog 应用 Django Haystack 全文检索与关键词高亮 Django 博客实现简单的全文搜索 开启 Django 博客的 RSS 功能 统计各个分类和标签下的文章数 稳定易用的 Django 分页库,完善分页功能 通过 Django Pagination 实现简单分页 在脚本中使用 ORM:Faker 批量生成测试数据 Django 官方推荐的姿势:类视图 Django 使用 union 合并不同模型(Model) 的查询集(QuerySet) 开发博客文章阅读量统计功能 使用 Certbot 向 Let's Encrypt 免费申请 HTTPS 证书 使用 Fabric 自动化部署 博客代码开源啦 (赠书)推荐一本django书籍:Django企业开发实战 Nginx+Gunicorn+Supervisor 部署 Django 博客应用 优化博客功能细节,提升使用体验 交流的桥梁:评论功能 分类、归档和标签页 页面侧边栏:使用自定义模板标签 自动生成文章摘要 - HelloDjango - Django博客教程(第二版) Markdown 文章自动生成目录,提升阅读体验 - HelloDjango - Django博客教程(第二版) 让博客支持 Markdown 语法和代码高亮 开发博客文章详情页 创作后台开启,请开始你的表演 博客从“裸奔”到“有皮肤” Django 的接客之道 Django 迁移、操作数据库 创建 Django 博客的数据库模型 开始进入 django 开发之旅 "空空如也"的博客应用 - HelloDjango - Django博客教程(第二版) 一种自顶而下的Python装饰器设计方法 Python提取支付宝和微信支付二维码 2018 - 我的学生生涯最后一年回顾 批量清除todo练习参考答案 筛选练习参考答案 删除todo练习参考答案 编辑todo练习参考答案 添加todo练习参考答案 标为完成练习参考答案 入门仪式_Hello_Vue练习参考答案 组件化todo应用 批量清除todo 本地存储 筛选 - Vue 2.x Todo 教程 还剩多少todo未完成 全部标为完成 自定义指令实现自动聚焦 删除todo 编辑todo 添加todo 标为完成 UI 显示todo列表 入门仪式:Hello Vue 在学习django-rest-framework时收集的学习资料推荐 区块链理论与应用研究小组成员招募书 - 追梦人物的博客 Python界网红,豆瓣工程师董伟明加了我的QQ后 - 追梦人物的博客 招募Django学习小组项目组核心成员
使用 Docker 让部署 Django 项目更加轻松 - HelloDjango
2019-10-14 · via 追梦人物的博客

之前一系列繁琐的部署步骤让我们感到痛苦。这些痛苦包括:

  • 要去服务器上执行 n 条命令
  • 本地环境和服务器环境不一致,明明本地运行没问题,一部署服务器上就挂挂,死活启动不起来
  • 如果上面的情况发生了,又要去服务器上执行 n 条命令以解决问题
  • 本地更新了代码,部署上线后,上述历史又重演一遍,想死的心都有了

那么我们有没有办法,让本地开发环境和线上环境保持一致?这样我们在部署上线前,就可以在本地进行验证,只要验证没问题,我们就有 99% 的把握保证部署上线后也没有问题(1%保留给程序玄学)。

这个办法就是使用 Docker。

Docker 是一种容器技术,可以为我们提供一个隔离的运行环境。要使用 Docker,首先我们需要编排一个镜像,镜像就是用来描述这个隔离环境应该是什么样子的,它需要安装哪些依赖,需要运行什么应用等,可以把它类比成一搜货轮的制造图。

有了镜像,就可以在系统中构建出一个实际隔离的环境,这个环境被称为容器,就好比根据设计图,工厂制造了一条船。工厂也可以制造无数条这样的船。

容器造好了,只要启动它,隔离环境便运行了起来。由于事先编排好了镜像,因此无论是在本地还是线上,运行的容器内部环境都一样,所以保证了本地和线上环境的一致性,大大减少了因为环境差异导致的各种问题。

所以,我们首先来编排 Docker 镜像。

类似于分离 settings.py 文件为 local.py 和 production.py,我们首先建立如下的目录结构,分别用于存放开发环境的镜像和线上环境的镜像:

HelloDjango-blog-tutorial\
      blog\
      ...
      compose\
            local\
            production\
                  django\
                  nginx\
    ...

local 目录下存放开发环境的 Docker 镜像文件,production 下的 django 文件夹存放基于本项目编排的镜像,由于线上环境还要用到 Nginx,nginx 目录下存放 Nginx 的镜像。

线上环境

镜像文件

我们先来在 production\django 目录下编排博客项目线上环境的镜像文件,镜像文件以 Dockerfile 命名:

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 . /app

COPY ./compose/production/django/start.sh /start.sh
RUN sed -i 's/\r//' /start.sh
RUN chmod +x /start.sh

首先我们在镜像文件开头使用 FROM python:3.6-alpine 声明此镜像基于 python:3.6-alpine 基础镜像构建。alpine 是一个 Linux 系统发行版,主打小巧、轻量、安全。我们程序运行需要 Python 环境,因此使用这个小巧但包含完整 Python 环境的基础镜像来构建我们的应用镜像。

ENV PYTHONUNBUFFERED 1 设置环境变量 PYTHONUNBUFFERED=1

接下来的一条 RUN 命令安装图像处理包 Pilliow 的依赖,因为如果使用 django 处理图片时,会使用到 Pillow 这个Python 库。

接着使用 WORKDIR /app 设置工作目录,以后在基于此镜像启动的 Docker 容器中执行的命令,都会以这个目录为当前工作目录。

然后我们使用命令 RUN pip install pipenv 安装 pipenv,-i 参数指定 pypi 源,国内一般指定为豆瓣源,这样下载 pipenv 安装包时更快,国外网络可以省略 -i 参数,使用官方的 pypi 源即可。

然后我们将项目依赖文件 Pipfile 和 Pipfile.lock copy 到容器里,运行 pipenv install 安装依赖。指定 --system 参数后 pipenv 不会创建虚拟环境,而是将依赖安装到容器的 Python 环境里。因为容器本身就是个虚拟环境了,所以没必要再创建虚拟环境。

接着将这个项目的文件 copy 到容器的 /app 目录下(当然有些文件对于程序运行是不必要的,所以一会儿我们会设置一个 dockerignore 文件,里面指定的文件不会被 copy 到容器里)。

然后我们还将 start.sh 文件复制到容器的 / 目录下,去掉回车符(windows 专用,容器中是 linux 系统),并赋予了可执行权限。

start.sh 中就是启动 Gunicorn 服务的命令:

#!/bin/sh

python manage.py migrate
python manage.py collectstatic --noinput
gunicorn blogproject.wsgi:application -w 4 -k gthread -b 0.0.0.0:8000 --chdir=/app

我们会让容器启动时去执行此命令,这样就启动了我们的 django 应用。--chdir=/app 表明以 /app 为根目录,这样才能找到 blogproject.wsgi:application。

在项目根目录下建立 .dockerignore 文件,指定 copy 到容器的文件:

.*
_credentials.py
fabfile.py
*.sqlite3

线上环境使用 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 http://hellodjango_blog_tutorial;
    }

    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

建立数据卷和容器中文件的映射关系。

同时这里要注意,数据卷只能映射文件夹而不能映射单一的文件,所以对我们应用的数据库来说,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'

volumes:
  database_local:

services:
  hellodjango_blog_tutorial_local:
    build:
      context: .
      dockerfile: ./compose/local/Dockerfile
    image: hellodjango_blog_tutorial_local
    container_name: hellodjango_blog_tutorial_local
    working_dir: /app
    volumes:
      - database_local:/app/database
      - .:/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 http://f1361db2.m.daocloud.io

在 docker 中运行一个 hello world,确认 docker 安装成功:

$ sudo docker run hello-world

docker 安装成功了,还要安装一下 docker-compose。其实是一个 python 包,我们直接通过 pip 安装就可以了:

$ pip install docker-compose

为了避免运行一些 docker 命令时可能产生的权限问题,我们把系统当前用户加入到 docker 组里:

$ sudo usermod -aG docker ${USER}

添加组后要重启一下 shell(ssh 连接的话就断开重连)。

万事俱备,只欠东风了!

开始准备让我们的应用在 docker 容器里运行。由于之前我们把应用部署在宿主机上,首先来把相关的服务停掉:

# 停掉 nginx,因为我们将在容器中运行 nginx
$ sudo systemctl stop nginx

# 停掉博客应用
$ supervisorctl stop hellodjango-blog-tutorial -c ~/etc/supervisord.conf

接下来拉取最新的代码到服务器,进入项目根目录下,创建线上环境需要的环境变量文件:

$ mkdir .envs
$ cd .envs
$ vi .production

将线上环境的 secret key 写入 .production 环境变量文件,

DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3

保存并退出。

回到项目根目录,运行 build 命令构建镜像:

$ docker-compose -f prodcution.yml build

然后我们可以开始启动根据构建好的镜像启动 docker 容器,不过为了方便,我们的 docker 进程仍然由 supervisor 来管理,我们修改一下博客应用的配置,让它启动时启动 docker 容器。

打开 ~/etc/supervisor/conf.d/hellodjango-blog-tutorial.ini,修改为如下内容:

[program:hellodjango-blog-tutorial]
command=docker-compose -f production.yml up --build
directory=/home/yangxg/apps/HelloDjango-blog-tutorial
autostart=true
autorestart=unexpected
user=yangxg
stdout_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stdout.log
stderr_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stderr.log

主要就是把之前的使用 Gunicorn 来启动服务换成了启动 docker。

修改 ini 配置 要记得 reread 使配置生效:

$ supervisorctl -c ~/etc/supervisord.conf
> reread
> start 

docker 容器顺利启动,访问我们的博客网站。抛掉镜像编排的准备工作,相当于我们只执行了一条构建容器并启动容器的命令就部署了我们的博客应用。如果换台服务器,也只要再执行一下镜像构建和启动容器的命令,服务就又可以起来!这就是 docker 的好处。

由于开发 django 用的最多的 IDE Pycharm 也能很好地集成 Docker,我现在开发工作已经全面拥抱 Docker 了,前所未有的体验,前所未有的方便和稳定,一定要学着用起来!

HTTPS

最后,由于 Nginx 在新的容器里运行,所以需要重新申请和配置 https 证书,这和之前是一样,只是此前 Nginx 在宿主机上,这次我们在容器里运行 certbot 命令。编排 nginx 镜像时已经安装了 certbot,直接执行命令即可,在 docker 容器内执行命令如下:

我们首先通过 docker ps 命令查看正在运行的容器,记住 nginx 容器的名字,然后使用 docker exec -it 容器名 命令的格式在指定容器内执行命令,所以我们执行:

$ docker exec -it nginx certbot --nginx

根据提示输入信息即可,过程和上一节在宿主机上部署一模一样,这里不再重复。

自动化部署

fabric 无需修改,来尝试本地执行一下:

pipenv run fab -H server_ip --prompt-for-login-password -p deploy

完美!至此,我们的博客已经稳定运行于线上,陆陆续续会有更多的人来访问我们的博客,让我们来继续完善它的功能吧!

-- EOF --