使用Windows电脑快速入门Docker

下载安装

最简单的学习docker的方式可能是docker desktop 配合 wsl 2。下载Docker Desktop这个软件后所有命令就都能在wsl上使用了。

image.png

因为之后需要在Linux服务器上进行部署,所以也不能单纯在docker desktop上玩,故下面的命令都是在wsl上跑。

# 打开powershell,查看自己的wsl版本
wsl --status
# 以root用户身份进入到wsl
wsl -u root
# 以root用户身份进入到wsl,并且直接进入到root目录下
wsl ~ -u root

image-20230903185902344

参考资料:

www.docker.com/

yeasy.gitbook.io/docker_prac…

www.bilibili.com/video/BV1CJ…

微软官方的WSL基本命令

Docker常见命令

镜像命令

查看镜像

docker images
docker images -q #查看所有的镜像id

搜索镜像

docker search 镜像名称

拉取镜像:从Docker仓库下载镜像到本地,镜像名称格式为 名称:版本号,如果版本号不指定则是最新的版本。如果不知道镜像版本,可以去dockerhub 搜索对应镜像查看。

容器相关

查看容器:

docker ps 是一个 Docker 命令,用于列出当前正在运行的容器。

ps 是 "Process Status" 的缩写,docker ps 命令的作用是显示 Docker 主机上正在运行的容器的状态信息,包括容器的 ID、名称、使用的镜像、运行状态、端口映射等。

当你执行 docker ps 命令时,Docker 将返回一个表格,其中包含当前正在运行的容器的详细信息。默认情况下,docker ps 仅显示正在运行的容器,不包括已停止的容器。

image-20230903230728009

如果你希望查看所有容器(包括已停止的容器),可以使用 docker ps -a 命令。

创建容器/运行容器:

在Docker中,docker rundocker create是两个常用的命令,用于创建和运行容器。它们之间的区别如下:

  • 创建容器 vs 运行容器:

    • docker create:该命令用于创建一个新的容器,但并不立即运行它。创建容器后,可以使用其他命令如docker start来启动该容器。创建容器时,可以指定容器的配置选项,但不会自动执行容器的命令。
    • docker run:该命令用于创建并运行一个新的容器。它是docker createdocker start两个步骤的组合。运行容器时,可以指定容器的配置选项,并在容器启动后立即执行容器的命令。
  • 容器生命周期:

    • docker create:创建容器后,容器将进入已创建(created)状态,并处于停止状态。需要使用docker start命令来启动容器,使其进入运行状态。
    • docker run:创建并运行容器后,容器将进入已运行(running)状态,并立即开始执行容器的命令。
  • docker create用于创建容器但不立即运行它,而docker run用于创建并运行容器。

    docker run
    • -i:保持容器运行。通过与-t一起同时使用,使用-it 创建容器后,会自动进入到容器中,退出容器后,容器会自动关闭。
    • -t:为容器分配一个伪终端
    • -d 用于在后台(detached mode)运行容器,需要使用docker exec进入容器,退出后,容器不会关闭
    • -it 创建的容器一般称之为交互式容器,-id创建的容器一般称为守护式容器
    • --name为创建的容器命名,如 --name=c1 名字叫c1
    docker run 镜像名:版本
    docker run -id --name=c1 centos

    进入容器:

    docker exec -it 容器名 命令
    # 例
    docker exec -it c1 /bin/bash

    其它命令

    启动容器:

    docker start 容器名/container id
    

    删除容器:

    docker rm 容器名/container id
    # 查看正在运行的容器的id (查看所有容器的id docker ps -aq)
    docker ps -q
    # 删除所有容器
    docker rm `docker ps -aq`

    查看容器的信息

    docker inspect 容器名/container id
    

    重启容器:

    docker restart 容器名/container id
    

    容器的数据卷

    概念

    在Docker中,数据卷(Data Volumes)是一种用于持久化存储数据的机制。数据卷可以在容器和主机之间共享和重用,使得容器中的数据在容器销毁或重启后仍然可用。

    数据卷提供了一种方便的方式来处理容器中的持久化数据。它们可以用于存储数据库文件、配置文件、日志文件以及其他需要持久化的应用数据。

    数据卷有以下特点:

  • 持久性:数据卷中的数据不会随着容器的销毁而丢失,因此可以在容器重启或重新部署后继续使用。
  • 共享性:数据卷可以在多个容器之间共享和重用,这样不同的容器可以访问相同的数据。
  • 生态系统集成:数据卷可以与其他Docker功能(如容器间的链接、网络等)进行集成,提供更灵活的应用部署和管理方式。
  • 数据卷可以通过两种方式在容器中使用:

  • 命名卷(Named Volumes):命名卷是通过指定名称创建的数据卷,Docker会在主机的文件系统中为每个命名卷创建一个目录,并将该目录映射到容器中的指定路径。命名卷的创建和管理由Docker引擎负责。
  • 挂载主机目录(Bind Mounts):挂载主机目录是将主机文件系统中的特定目录直接挂载到容器中的指定路径,从而实现数据共享。使用挂载主机目录,可以直接将主机上的文件或目录与容器中的路径相关联。
  • 当创建数据卷时,可以选择使用命名卷(Named Volumes)或挂载主机目录(Bind Mounts)这两种方式。下面我将分别介绍它们的创建方式和特点。

    挂载主机目录(Bind Mounts)

    • 创建挂载主机目录:指定主机文件系统中的目录作为挂载点。例如:/path/on/host
    • 在容器中使用挂载主机目录:在运行容器时,使用-v--mount参数将主机目录与容器中的路径关联起来。例如:docker run -v /path/on/host:/path/to/containerdocker run --mount type=bind,source=/path/on/host,target=/path/to/container
    • 特点:
      • 挂载主机目录将主机的特定目录直接映射到容器中,容器可以直接读取和写入主机文件系统中的数据。
      • 挂载主机目录提供了更高的灵活性,可以使用主机上的任意目录作为数据卷。
      • 挂载主机目录需要手动创建和配置主机目录,主机上的数据变动会直接影响容器中的数据。

    在挂载的本机目录下创建了文件,在容器上也能看到该文件。

    # 创建容器 将本机的目录挂载到docker容器上,如果目录不存在会自动被创建
    docker run -it --name=c1 -v /root/data:/root/data_container centos:latest
    # 一个容器挂载多个目录 表示换行
    docker run -it --name=c2 -v /root/data:/root/containerData1
    -v /root/data2:/root/containerData2 centos:latest

    本机:

    本机

    容器:

    image-20230827224639851

    同样,在容器上对挂载目录做出修改,在主机上也能看到变化:

    容器:

    image-20230827224827681

    主机:

    image-20230827224913241

    命名卷(Named Volumes)

    • 创建命名卷:使用docker volume create命令创建命名卷,并为其指定一个名称。例如:docker volume create myvolume
    • 在容器中使用命名卷:在运行容器时,使用-v--mount参数将命名卷与容器中的路径关联起来。例如:docker run -v myvolume:/path/to/containerdocker run --mount source=myvolume,target=/path/to/container
    • 特点:
      • Docker引擎负责命名卷的创建和管理,无需手动创建和配置主机目录。
      • 命名卷的数据存储在主机的文件系统中的特定目录中,可以在不同的容器之间共享和重用。
      • 命名卷的生命周期与容器的生命周期相互独立,即使容器被删除,命名卷中的数据仍然存在。

    查看数据卷的具体信息

    在主机里使用以下命令可以查看容器的信息:

    docker inspect 容器名/容器id
    

    挂载主机的目录配置在"mount"下面:

    {
    "Mounts": [
    {
    "Type": "bind",
    "Source": "/root/data",
    "Destination": "/root/containerData1",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
    },
    {
    "Type": "bind",
    "Source": "/root/data2",
    "Destination": "/root/containerData2",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
    }
    ]
    }

    多容器间的数据交换

    挂载到同一个数据卷

    可以通过把本机中同一个数据卷挂载到2个不同容器中,就可以间接实现数据交换了:

    image-20230827230629076

    docker run -it --name=c1 -v ~/data:/root/c1Data centos
    docker run -it --name=c2 -v ~/data:/root/c2Data centos

    image-20230827231322711

    数据卷容器

    数据卷容器(Data Volume Container)是本身是一个特殊的容器,专门用于创建和管理数据卷,并与其他容器共享数据。

    image-20230827232016576转存失败,建议直接上传图片文件

  • 创建数据卷容器:可以使用 docker create 来创建一个普通的容器:

    docker create --name=dataVolumeContainer -v /容器目录 centos
    
  • 其他容器(必须使用run创建)使用--volumes-from 来挂载该数据卷容器,且不管该数据卷容器是否在运行。

    docker run it --name=c4 --volumes-from dataVolumeContainer centos
    
  • Docker应用部署

    • 容器内的网络服务和外部的机器不能通信,但外部机器内和宿主机可直接通信,且宿主机和容器可以直接通信
    • 当容器中的网络服务需要被外部机器访问时,可以将容器中提供服务的端口映射到宿主机的端口上。外部机器访问宿主机的该端口,从而间接访问容器的服务,这种操作称为端口映射

    image.png

    MySQL部署

    在docker容器容器中部署MySQL,并通过外部的MySQL客户端来操作MySQL Server

  • 搜索mysql镜像
  • docker search mysql
    
  • 拉取mysql镜像
  • docker pull mysql
    
  • 创建容器,设置端口映射、目录映射
  • # 在/root目录下创建mysql目录用于存储mysql数据信息
    mkdir ~/mysql
    cd ~/mysql
    docker run -id
    -p 3307:3306
    --name=c_mysql
    -v $PWD/conf:/etc/mysql/conf.d
    -v $PWD/logs:/logs
    -v $PWD/data:/var/lib/mysql
    -e MYSQL_ROOT_PASSWORD=123456
    mysql
    • 参数说明:
      • -p 3307:3306:将容器的 3306 端口映射到宿主机的 3307 端口。
      • -v $PWD/conf:/etc/mysql/conf.d:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf。配置目录
      • -v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs。日志目录
      • -v $PWD/data:/var/lib/mysql :将主机当前目录下的data目录挂载到容器的 /var/lib/mysql 。数据目录
      • **-e MYSQL_ROOT_PASSWORD=123456:**初始化 root 用户的密码。

    一般容器的端口映射到主机时,2者的端口会写得一样,这里为了强调是3307是主机,写在冒号前,3306是容器,写在冒号后,所以写得不一样。

    接着,我们可以进入到mysql:

    docker exec -it c_mysql /bin/bash
    

    然后,输入密码登录mysql server:

    mysql -u root -p 
    

    Tomcat部署

  • 搜索tomcat镜像
  • docker search tomcat
    
  • 拉取tomcat镜像
  • docker pull tomcat
    
  • 创建容器,设置端口映射、目录映射
  • # 在/root目录下创建tomcat目录用于存储tomcat数据信息
    mkdir ~/tomcat
    cd ~/tomcat
    docker run -id --name=c_tomcat
    -p 8080:8080
    -v $PWD:/usr/local/tomcat/webapps
    tomcat
    • 参数说明:
      • **-p 8080:8080:**将容器的8080端口映射到主机的8080端口

        **-v $PWD:/usr/local/tomcat/webapps:**将主机中当前目录挂载到容器的webapps

    Nginx部署

  • 搜索nginx镜像
  • docker search nginx
    
  • 拉取nginx镜像
  • docker pull nginx
    
  • 创建容器,设置端口映射、目录映射
  • # 在/root目录下创建nginx目录用于存储nginx数据信息
    mkdir ~/nginx
    cd ~/nginx
    mkdir conf
    cd conf
    # 在~/nginx/conf/下创建nginx.conf文件,粘贴下面内容
    vim nginx.conf
    user nginx;
    worker_processes 1;
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;
    events {
    worker_connections 1024;
    }
    http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    #tcp_nopush on;
    keepalive_timeout 65;
    #gzip on;
    include /etc/nginx/conf.d/*.conf;
    }
    docker run -id --name=c_nginx
    -p 80:80
    -v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf
    -v $PWD/logs:/var/log/nginx
    -v $PWD/html:/usr/share/nginx/html
    nginx
    • 参数说明:
      • -p 80:80:将容器的 80端口映射到宿主机的 80 端口。
      • -v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf:将主机当前目录下的 /conf/nginx.conf 挂载到容器的 :/etc/nginx/nginx.conf。配置目录
      • -v $PWD/logs:/var/log/nginx:将主机当前目录下的 logs 目录挂载到容器的/var/log/nginx。日志目录
  • 如果在宿主机的html文件夹下创建一个index.html,然后访问ip:80就能访问运行在容器的页面了。
  • 部署Redis

  • 搜索redis镜像
  • docker search redis
    
  • 拉取redis镜像
  • docker pull redis
    
  • 创建容器,设置端口映射
  • docker run -id --name=c_redis -p 6379:6379 redis
    
  • 使用外部机器连接redis
  • ./redis-cli.exe -h 192.168.149.135 -p 6379
    

    Dockerfile

    Docker镜像原理

    思考:

  • Docker 镜像本质是什么?
    Docker 镜像是一种轻量级、独立的可执行软件包,其中包含了运行特定应用程序所需的一切:代码、运行时环境、系统工具、系统库等。可以将镜像看作是一个只读模板,用于创建 Docker 容器。镜像通过层(layers)的方式进行组织,每个层都包含了文件系统的一部分,多个层的叠加组合形成了完整的镜像。镜像的本质是一个可执行的文件,可以被分发、存储和加载到 Docker 引擎中。
  • image.png

  • Docker中一个centos镜像为什么只有200MB,而一个centos操作系统的iso文件要几个个G?
    Docker 镜像与操作系统的 ISO 文件之间存在一些关键区别。ISO 文件是一个完整的操作系统安装映像,包含了操作系统的所有组件、库和工具,以及默认安装的应用程序和配置。它旨在提供一个完整的操作系统环境,以便用户可以在物理机器或虚拟机上进行安装。
    相比之下,Docker 镜像是基于容器化技术的,它利用操作系统的内核并与宿主机共享操作系统资源。Docker 镜像通常采用分层存储的方式,每个层都只包含了应用程序或组件的变化部分,这种共享层的机制使得镜像可以高效地共享和重用。

    当创建 CentOS 镜像时,Docker 可以基于一个基础镜像(例如官方提供的 CentOS 镜像)进行构建,然后在其上添加所需的应用程序和配置。这样,镜像中的每个层都只包含了变化的部分,而不需要重复存储操作系统本身,从而大大减小了镜像的大小。

  • Docker中一个tomcat镜像为什么有500MB,而一个tomcat安装包只有70多MB?
    类似于 CentOS 镜像的情况,Docker 镜像中的 Tomcat 镜像也采用了分层存储的机制。Tomcat 安装包只包含了 Tomcat 服务器本身的二进制文件和所需的库文件,而 Docker 镜像中的 Tomcat 镜像除了包含 Tomcat 本身,还包含了一个基础操作系统镜像以及其他可能需要的依赖项。这些附加的层(如基础操作系统层、库文件层等)增加了镜像的大小。

  • Linux文件系统由 bootfsrootfs 两部分组成:

    • bootfs:包含 bootloader(引导加载程序)和 kernel(内核)
    • rootfs: 是root文件系统,就是典型的Linux系统中的/dev,/proc,/bin,/etc等标准执行目录和程序
    • 不同的linux发行版,bootfs基本相同,而rootfs不同(比如centos和ubuntu)

    Docker镜像制作

    Docker镜像如何制作?

  • 容器转为镜像 (使用较少)

    docker commit 容器id 镜像名称:版本号 # 根据容器生成镜像
    docker save -o 压缩文件名称 镜像名称:版本号 # 压缩
    # 加载
    docker load -i 压缩文件名称
  • Dockerfile

    Dockerfile是用于构建Docker镜像的文本文件,它包含了一系列的指令和配置,用于定义镜像的构建过程和运行环境。

    关键字作用备注
    FROM指定父镜像指定 Dockerfile 基于哪个镜像构建
    LABEL标签标明 Dockerfile 的标签,可以在 Docker 镜像的基本信息中查看
    RUN执行命令执行一段命令,默认使用 /bin/sh 格式:RUN command 或者 RUN ["command"]
    CMD容器启动命令启动容器时的默认命令,与 ENTRYPOINT 配合使用
    COPY复制文件在构建过程中将文件复制到镜像中
    ADD添加文件在构建过程中添加文件到镜像中,不仅限于当前构建上下文,可以来自远程服务
    ENV环境变量指定构建时的环境变量,可以在启动容器时使用 -e 覆盖
    ARG构建参数构建过程中使用的参数,只在构建时有效,如果有相同名字的 ENV,ENV 会覆盖 ARG
    VOLUME定义可挂载的数据卷指定哪些目录在启动容器时可以挂载到文件系统中,使用 -v 绑定
    EXPOSE暴露端口定义容器运行时监听的端口,使用 -p 来绑定
    WORKDIR工作目录指定容器内部的工作目录,如果不存在则自动创建,可以使用绝对或相对路径
    USER指定执行用户指定在 RUN、CMD、ENTRYPOINT 执行命令时使用的用户
    HEALTHCHECK健康检查指定检测容器健康状态的命令,一般应用本身有健康检查机制,该指令用处不大
    ONBUILD触发器当基础镜像中存在 ONBUILD 关键字时,在执行 FROM 后会执行 ONBUILD 命令
    STOPSIGNAL发送退出信号设置发送给容器的系统调用信号以退出
    SHELL指定执行脚本的 Shell指定在 RUN、CMD、ENTRYPOINT 执行命令时使用的 Shell

    生成镜像:

    docker build -t .
    # docker build -t myimage:1.0 .
    # -t 设置标签
    # . 读取当前目录下的dockerfile
    # -f 设置此次生成镜像读取哪个路径下的dockerfile
  • DockerFile案例

    案例一

    自定义centos7镜像,要求:1. 默认登录后的路径是/usr 2. 能够使用vim命令

    # 定义父镜像 set the base image
    FROM centos:7
    # 定义作者信息
    LABEL maintainer="jiaqi"
    # 执行安装vim 在 RUN yum install -y vim 指令中,运行 yum clean all 来清理 yum 缓存。
    RUN yum install -y vim && yum clean all
    # 定义默认的工作路径
    WORKDIR /usr
    # 定义容器启动执行的命令:
    CMD ["/bin/bash"]

    image-20230903182528136

    案例二

    给一个Node.js应用编写Dockerfile,这里我使用自己的一个小项目,可以参考这篇神光大佬的文章来写。

    # 构建阶段
    FROM node:18.17-alpine3.17 as build-stage
    WORKDIR /server
    COPY ./server/package.json ./server/package-lock.json ./
    RUN npm install
    COPY ./server .
    RUN npm run build
    ARG port=4000
    # 生成最后的镜像
    FROM node:18.17-alpine3.17 as production-stage
    WORKDIR /server
    COPY --from=build-stage ./server/dist ./
    COPY ./server/package.json ./server/package-lock.json ./
    RUN npm install --production
    ENV PORT=$port
    EXPOSE ${port}
    CMD ["node", "app.js"]

    我修改了几次后,就顺利跑通了,第一次看到自己项目跑到docker容器里面,内心多少有点小激动!

    image-20230903225950241

    不过,这只是第一步,因为我的项目还有使用mongoDBNginx,需要使用Docker Compose把它们一起跑起来😉。

    服务编排

    Docker Compose

    Docker Compose 是一个编排多容器分布式部署的工具,提供命令集管理容器化应用的完整开发周期,包括服务构建启动和停止。使用步骤:

  • 利用Dockerfile定义运行环境镜像
  • 使用compose.yaml定义组成应用各服务
  • 运行docker compose up(docker compose v1 使用docker-compose up命令)启动应用
  • 使用

    可以在这里找到下载和安装方法。

    我使用的是wsl2 +windows docker destop 来学习docker的,docker desktop已经帮我把安装这一步干好了,所以不需要在WSL中安装docker compose。

    # 进入wsl ,查看自己是否已经安装好了
    root@jiaqi:~# docker-compose -v
    Docker Compose version v2.20.2-desktop.1

    我这里想要实现的用compose串联起 Nginx,Node,MongoDB。

    编排MongoDB和Node

    事情得一步一步来进行,特别是对于我这样的新手来说。

    第一步,我们先让MongoDB和Node能够一起运行。

    基于以下几个要点:

    • 先把数据库跑起来,然后再跑后端服务 (所以这里backend加了一个depends_on: mongo)
    • 数据库和后端运行在同一网络下(这里将网络命名为mongo,并且分别指定了backend和mongo使用网络mongo)
    • 因为我的后端服务代码中MONGO_URI是从环境变量中读取的,所以这里还设置了一下环境变量
    services:
    backend:
    restart: always
    build:
    context: ./server
    dockerfile: ./Dockerfile
    environment:
    - MONGO_URI=mongodb://mongo:27017
    ports:
    - 4000:4000
    depends_on:
    - mongo
    stdin_open: true
    networks:
    - mongo
    mongo:
    image: mongo
    restart: always
    networks:
    - mongo
    expose:
    - 27017
    networks:
    mongo:
  • services:这是一个服务定义的部分,用于定义要运行的各个容器服务。
  • backend:这是一个名为backend的服务定义,它是后端服务器的容器。
    • restart: always:指定在容器退出时总是重新启动容器。
    • build:指定构建该服务所需的参数。
      • context: ./server:指定构建上下文的路径,即包含后端服务器代码的目录。
      • dockerfile: ./Dockerfile:指定用于构建该服务的Dockerfile的路径。
    • environment:指定容器中的环境变量。
      • MONGO_URI=mongodb://mongo:27017:设置名为MONGO_URI的环境变量,指定MongoDB的连接URI。
    • ports:指定容器的端口映射。
      • 4000:4000:将主机的4000端口映射到容器的4000端口,使得可以通过主机的4000端口访问后端服务。
    • depends_on:指定该服务所依赖的其他服务。
      • mongo:该服务依赖于名为mongo的服务,即MongoDB数据库服务。
    • stdin_open: true:保持标准输入打开,以便可以与容器进行交互。
    • networks:指定该服务所连接的网络。
      • mongo:将该服务连接到名为mongo的网络中。
  • mongo:这是一个名为mongo的服务定义,它是MongoDB数据库的容器。
    • image: mongo:使用名为mongo的Docker镜像作为容器基础。
    • restart: always:指定在容器退出时总是重新启动容器。
    • networks:指定该服务所连接的网络。
      • mongo:将该服务连接到名为mongo的网络中。
    • expose:指定容器所暴露的端口。
      • 27017:暴露容器的27017端口,以允许其他容器连接到MongoDB数据库。
  • networks:这是一个网络定义的部分,用于定义容器之间的网络。
    • mongo:定义了一个名为mongo的网络,该网络用于连接backendmongo这两个服务。
  • 总体而言,该Dockerfile定义了两个服务:一个后端服务和一个MongoDB数据库服务,它们分别运行在独立的容器中,并通过网络进行连接。后端服务在容器的4000端口提供服务,并通过环境变量指定了MongoDB的连接URI。MongoDB服务则暴露容器的27017端口,以供其他容器连接。

    最后,将它们跑起来:

    image.png

    image-20230916162536710

    我的浏览器就能直接访问我的后端服务localhost:4000

    image-20230916162730020

    增加Nginx

    后端编排成功后,我还需要实现使用Nginx反向代理,从而为之后使用Let's encrypt做好准备。我的Nignx配置需要实现:

    • 反向代理4000端口
    • 挂载sites-available目录,因为之后会使用certbot,certbot会修改/etc/nginx/sites-available目录
    services:
    backend:
    restart: always
    build:
    context: ./server
    dockerfile: ./Dockerfile
    environment:
    - MONGO_URI=mongodb://mongo:27017
    ports:
    - 4000:4000
    depends_on:
    - mongo
    stdin_open: true
    networks:
    - mongo
    mongo:
    image: mongo
    restart: always
    networks:
    - mongo
    expose:
    - 27017
    ports:
    - 27017:27017
    nginx:
    image: nginx:1.25.2-alpine
    restart: always
    ports:
    - 80:80
    - 443:443
    volumes:
    - /etc/nginx/sites-available/:/etc/nginx/sites-available/
    - /etc/nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
    - backend
    networks:
    - mongo
    networks:
    mongo:

    这里sites-avaliable文件交的Nignx配置可以见这篇文章。

    server {
    listen 80 ;
    listen [::]:80 ;
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    return 301 https://$host$request_uri;
    }
    server {
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name example.org; # managed by Certbot
    location / {
    proxy_pass http://localhost:4000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }

    nginx.conf的配置如下:

    worker_processes auto;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    events {
    worker_connections 768;
    # multi_accept on;
    }
    http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;
    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    ##
    # SSL Settings
    ##
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    gzip on;
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    }

    把这些文件挂载好,之后再使用certbot的命令获得免费的SSL认证。