Docker的使用

Docker的使用

一、前言

1. 什么是Docker

参考:https://docker_practice.gitee.io/zh-cn/container/daemon.html

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker 项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)。

Docker 自开源后受到广泛的关注和讨论,至今其 GitHub 项目 已经超过 5 万 7 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆,在 2013 年底,dotCloud 公司决定改名为 Docker。Docker 最初是在 Ubuntu 12.04 上开发实现的;Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持;Google 也在其 PaaS 产品中广泛应用 Docker。

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。

2. 为什么要使用Docker

作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

  1. 更高效的利用系统资源
    由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。

  2. 更快速的启动时间
    传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。

  3. 一致的运行环境
    开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。

  4. 持续交付和部署
    对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。

使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。

  1. 更轻松的迁移
    由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。

  2. 更轻松的维护和扩展
    Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

二、基本概念

1. 镜像

我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

2. 容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

3. 仓库

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。

Docker Registry 公开服务
Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。

最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。除此以外,还有 Red Hat 的 Quay.io;Google 的 Google Container Registry,Kubernetes 的镜像使用的就是这个服务。

由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为 加速器。常见的有 阿里云加速器、DaoCloud 加速器 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。在 安装 Docker 一节中有详细的配置方法。

国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 网易云镜像服务、DaoCloud 镜像市场、阿里云镜像库 等。

私有 Docker Registry
除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。在 私有仓库 一节中,会有进一步的搭建私有 Registry 服务的讲解。

开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 Docker Trusted Registry 中,提供了这些高级功能。

除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,Harbor 和 Sonatype Nexus。

三、CentOS安装Docker

1. 准备工作
1.1 系统要求

Docker 支持 64 位版本 CentOS 7/8,并且要求内核版本不低于 3.10。 CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无法使用,并且部分功能可能不太稳定。

旧版本的 Docker 称为 docker 或者 docker-engine,使用以下命令卸载旧版本:

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
2. 使用yum安装
  • 安装依赖包

    sudo yum install -y yum-utils
    
  • 添加yum软件源

    # 鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
    # 执行下面的命令添加 yum 软件源:
    $ sudo yum-config-manager \
        --add-repo \
        https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
    
    $ sudo sed -i 's/download.docker.com/mirrors.ustc.edu.cn\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
    
    
3. 安装Docker
# 更新 yum 软件源缓存,并安装 docker-ce。
$ sudo yum install docker-ce docker-ce-cli containerd.io
4. 使用脚本自动安装

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 --mirror 选项使用国内源进行安装:

若你想安装测试版的 Docker(或你的系统是 CentOS 8), 请从 test.docker.com 获取脚本

# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud

# 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
5. 启动Docker
$ sudo systemctl enable docker
$ sudo systemctl start docker
6. 测试安装成功
$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
d1725b59e92d: Pull complete
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

若能正常输出以上信息,则说明安装成功。

7. 镜像加速

如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker 国内镜像加速

国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,例如:

由于镜像服务可能出现宕机,建议同时配置多个镜像。各个镜像站测试结果请到 docker-practice/docker-registry-cn-mirror-test 查看。

国内各大云服务商(腾讯云、阿里云、百度云)均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务,具体请参考本页最后一小节。

本节我们以 网易云 镜像服务 https://hub-mirror.c.163.com 为例进行介绍。

目前主流 Linux 发行版均已使用 systemd 进行服务管理,这里介绍如何在使用 systemd 的 Linux 发行版中配置镜像加速器。

请首先执行以下命令,查看是否在 docker.service 文件中配置过镜像地址。

$ systemctl cat docker | grep '\-\-registry\-mirror'

如果该命令有输出,那么请执行 $ systemctl cat docker 查看 ExecStart= 出现的位置,修改对应的文件内容去掉 --registry-mirror 参数及其值,并按接下来的步骤进行配置。

如果以上命令没有任何输出,那么就可以在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

{
  "registry-mirrors": [
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ]
}

注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。

之后重新启动服务。

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

检查加速器是否生效

执行 $ docker info,如果从结果中看到了如下内容,说明配置成功。

Registry Mirrors:
 https://hub-mirror.c.163.com/

四、使用镜像

1. 获取镜像
1.1 pull获取镜像

在之前的介绍中,我们知道镜像是 Docker 的三大组件之一。

Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。

之前提到过,Docker Hub 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。

从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。

  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)。
  • 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

比如:

$ docker pull ubuntu:18.04

上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:18.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 18.04 的镜像。

从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。

在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 sha256 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。

如果从 Docker Hub 下载镜像非常缓慢,可以参照 镜像加速器 一节配置加速器。

1.2 运行容器

有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:18.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。

$ docker run -it --rm ubuntu:18.04 bash

docker run 就是运行容器的命令,具体格式我们会在 容器 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。

  • -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
  • ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash

进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。

最后我们通过 exit 退出了这个容器。

2. 列出镜像

要想列出已经下载下来的镜像,可以使用 docker image lsdocker images命令。

$ docker image ls
REPOSITORY         TAG                 IMAGE ID            CREATED           SIZE
redis              latest              5f515359c7f8        5 days ago        183 MB
nginx              latest              05a60462f8ba        5 days ago        181 MB
mongo              3.2                 fe9198c04d62        5 days ago        342 MB
<none>           <none>              00285df0df87        5 days ago          342 MB
ubuntu             18.04               f753707788c5        4 weeks ago       127 MB
ubuntu             latest              f753707788c5        4 weeks ago       127 MB

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个 标签。因此,在上面的例子中,我们可以看到 ubuntu:18.04ubuntu:latest 拥有相同的 ID,因为它们对应的是同一个镜像。

  • 镜像体积

如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,ubuntu:18.04 镜像大小,在这里是 127 MB,但是在 Docker Hub 显示的却是 50 MB。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。

3. 删除本地镜像
$ docker rmi <image-id>
4. 删除虚悬镜像<none>

上面的镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 <none>。:

<none>         <none>          00285df0df87      5 days ago          342 MB

这个镜像原本是有镜像名和标签的,原来为 mongo:3.2,随着官方镜像维护,发布了新版本后,重新 docker pull mongo:3.2 时,mongo:3.2 这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 <none>。除了 docker pull 可能导致这种情况,docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 <none> 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像:

$ docker image ls -f dangling=true
REPOSITORY        TAG               IMAGE ID          CREATED           SIZE
<none>            <none>            00285df0df87        5 days ago          342 MB

一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。

$ docker image prune

五、操作容器

1. 概念
容器是 Docker 又一核心概念。

简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。

本章将具体介绍如何来管理一个容器,包括创建、启动和停止等。
2. 启动容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。

因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。

2.1 新建并启动

所需要的命令主要为 docker run

例如,下面的命令输出一个 “Hello World”,之后终止容器。

$ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world
  • 下面的命令则启动一个 bash 终端,允许用户进行交互。
$ docker run -it ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#

其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止
2.2 退出容器
$ docker run -it ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/# exit

# 使用exit退出容器后,容器会停止
2.3 后台运行

在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。

# 启动一个redis服务 此时会以前台模式启动
$ docker run -it redis:5 

1:C 15 Dec 2020 08:55:49.016 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 15 Dec 2020 08:55:49.016 # Redis version=5.0.10, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 15 Dec 2020 08:55:49.016 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.10 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

1:M 15 Dec 2020 08:55:49.017 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 15 Dec 2020 08:55:49.017 # Server initialized
1:M 15 Dec 2020 08:55:49.017 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 15 Dec 2020 08:55:49.017 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 15 Dec 2020 08:55:49.018 * Ready to accept connections

  • 后台启动
$ docker run -d redis:5
2.4 后台启动特例(了解)
# ubuntu默认cmd是bash 此时无输入 该行命令执行完主进程结束 容器就会退出运行
$ docker run -d ubuntu:18.04
# 解决:
$ docker run -itd ubuntu:18.04 阻塞

或 针对所有的通用指令
$ docker run -d python:3.7.9-buster tail -f /dev/null
2.5 再次进入容器
$ docker exec -it 69d1 bash 或 sh
root@25827590f1f2:/data#  exit  不会让容器停止    -- 开启了一个新的进程

或 

$ docker attach   69d1  
root@25827590f1f2:/data#  exit  会让容器停止 
2.6 删除容器
# 根据id删除或强制删除一个或多个容器
$ docker rm [-f] <container-id> [container-id...]

# 或 删除已经停止的容器
$ docker container prune

# 或 根据特定条件删除容器
$ docker ps -a | grep <关键字> |awk '{print $1}' | xargs  docker rm -f
2.7 启动一个Mysql容器
$ docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
参数说明:

-p 3306:3306 :映射容器服务的 3306 端口到宿主机的 3306 端口,外部主机可以直接通过 宿主机ip:3306 访问到 MySQL 的服务。
MYSQL_ROOT_PASSWORD=123456:设置 MySQL 服务 root 用户的密码

六、Docker部署Django项目

1. 基于Python基础镜像
  • 以后台模式运行一个Python镜像的容器
$ docker run -itd -p 8000:8000 -v ~/django_test_project:/app python:3.7.9-buster

# 映射8000端口
# 将项目文件夹映射到容器的/app目录下
  • 进入容器
$ docker exec -it <容器id> bash
  • 安装依赖
root@dd87391cd196:/app#  pip install -r requirements.txt -i https://pypi.douban.com/simple
  • 启动服务
root@dd87391cd196:/app#   python manager.py runserver 0.0.0.0:8000
2. 使用uwsgi启动服务
[uwsgi]
#配置和nginx连接的socket连接
socket=0.0.0.0:8080
#也可以使用http
#http=0.0.0.0:8080
#配置项目路径,项目的所在目录
chdir=/home/django_test
#配置wsgi接口模块文件路径
wsgi-file=django_test/wsgi.py
#配置启动的进程数
processes=4
#配置每个进程的线程数
threads=2
#配置启动管理主进程
master=True
#配置存放主进程的进程号文件
pidfile=uwsgi.pid
#配置dump日志记录
daemonize=uwsgi.log
uwsgi --ini uwsgi.ini #启动
lsof -i :8001    #按照端口号查询
ps aux | grep uwsgi   #按照程序名查询
kill -9 13844       #杀死进程
uwsgi --stop uwsgi.pid      #通过uwsg停止uwsgi
uwsgi --reload uwsgi.pid  #重启
3. Nginx服务
# 在项目根目录下创建一个nginx.conf文件
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
          proxy_pass http://uwsgi容器的名字:8080;
        }  
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

# 如果uwsgi容器没有指定名字,则需要使用docker给定的名字或重命名
$ docker container rename 容器id test-uwsgi
# 且nginx容器和uwsgi容器,需要在同一个网络
$ docker network create test-network   创建一个新的网络
$ docker network connect test-network dd 将dd容器连接到新的网络

$ docker run -d --network test-network -p 81:80 -v ~/django_test_project/nginx.conf:/etc/nginx/nginx.conf nginx:1.16-alpine

# 启动nginx容器 访问81端口即可

但是上述的部署方式并不推荐,原因:

  • 这种方式和在虚拟机中部署项目没有什么区别
  • 容器销毁时,安装的依赖等都会消失,再次run时需要重新安装依赖等
  • 虽然可以将安装好依赖的容器打包成一个镜像,再用该镜像去生成容器,但是它是黑箱操作,并不知道容器内安装了哪些依赖
  • 容器应该保持无状态,安装依赖应该在run启动容器时进行操作,而不是创建好容器后,进入容器再安装依赖,否则它就就成了有状态的容器了(依赖在存储层),存储层的数据会随着容器销毁而丢失

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFA2YoWm-1618843847739)(image-20201216164023365.png)]

七、Dockerfile定制镜像

1. Dockerfile简介

Dockerfile 是一个文 一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

2. 创建Dockerfile
# 在一个空白目录中 vi Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
3. 构建镜像
$ docker build -t nginx:v3 .
4. 运行容器
$ docker run -d -p 82:80 nginx:v3

八、Dockerfile指令详解

九、Dockerfile部署Django项目

1. 使用uwsgi
# 在项目根目录下,添加uwsig.ini文件
[uwsgi]
#uWSGI和nginx通信的port
http = 0.0.0.0:9000 
# the base directory (full path)
chdir = /app
# Django's wsgi file
wsgi-file = ems_project/wsgi.py
# maximum number of worker processes
processes = 4
#thread numbers startched in each worker process
threads = 2
#monitor uwsgi status 通过该端口可以监控 uwsgi 的负载情况
# clear environment on exit
vacuum = true
pidfile = uwsgi.pid
#daemonize-run ,file-to-record-log
static-map = /static=static
# 在项目根目录下创建Dockerfile文件
FROM python:3.7.9-buster

COPY requirements.txt /tmp

RUN set -eux; \
        pip install --upgrade pip -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        pip install -r /tmp/requirements.txt -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        rm -f /tmp/requirements.txt

EXPOSE 9000

CMD ["uwsgi", "--ini", "/app/uwsgi.ini"]
  • 打包镜像 docker build -t ems-uwsgi:v1 . 只有当依赖发生修改时才需要重新打包
  • 启动容器docker run -d -v ~/ems_project:/app -p 9000:9000 ems-uwsgi:v1
2. 使用mysql
1. 创建数据卷 用于保存mysql的数据
		docker volume create ems-mysql-data
		
2. 创建网络
		docker network create ems-network
		
3. 启动MySQL容器 	
		docker run --network ems-network --name ems-mysql -v ems-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
	
    	网络必须和web服务处于同一个网络
    	同时需要指定容器的名字,用于数据库的配置中的host
    	
4. 进入MySQL建库
		docker exec -it 3d sh
		mysql -uroot -p123456
		
5. 修改settings.py
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME': 'ems',
                'HOST': 'ems-mysql',  # 第三步中的--name
                'PORT': 3306,
                'USER': 'root',
                'PASSWORD': '123456'
            }
        }

6. 修改requirements.txt 添加数据库驱动
		mysqlclient
	
7. 打包镜像	
		docker build -t  ems-uwsgi:v1 .		
		
8. 启动容器
		docker run -d -v ~/ems_project:/app --name ems-uwsgi --network ems-network ems-uwsgi:v1
		
如果访问出错,需要进入到uwsgi所在的容器,执行迁移指令		
3. 使用nginx
1. 在项目目录下,准备nginx配置文件 
        worker_processes  1;
        events {
            worker_connections  1024;
        }
        http {
            include       mime.types;
            default_type  application/octet-stream;
            sendfile        on;
            keepalive_timeout  65;
            server {
                listen       80;
                #server_name  localhost;
                location / {
                  #uwsgi_pass 101.133.225.166:8080;
                  proxy_pass http://ems-uwsgi:9000;
                }
            }
        }
        
2. 启动uwsgi容器
		docker run -d -v ~/ems_project:/app --name ems-uwsgi --network ems-network ems-uwsgi:v1
		
3. 启动nginx容器
		docker run -d --network ems-network -p 81:80 -v ~/ems_project/nginx.conf:/etc/nginx/nginx.conf nginx:1.16-alpine	
  • 使用nginx处理静态资源
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        #server_name  localhost;
        location / {
          #uwsgi_pass 101.133.225.166:8080;
          proxy_pass http://ems-uwsgi:9000;
        }
       
        location /static {
           alias /static;
        }
    }
}

# 启动nginx容器
docker run -d --network ems-network -p 81:80 -v ~/ems_project/nginx.conf:/etc/nginx/nginx.conf -v ~/ems_project/static:/static nginx:1.16-alpine

十、Docker Compose

1. 简介

通过第一部分中的介绍,我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

2. 基本使用
2.1 场景

最常见的项目是 web 网站,该项目应该包含 web 应用和缓存。

下面我们用 Python 来建立一个能够记录页面访问次数的 web 网站。

2.2 web 应用

新建文件夹,在该目录中编写 app.py 文件

from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host='redis', port=6379)

@app.route('/')
def hello():
    count = redis.incr('hits')
    return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
2.3 Dockerfile

编写 Dockerfile 文件,内容为

FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
2.4 docker-compose.yml

编写 docker-compose.yml 文件,这个是 Compose 使用的主模板文件。

version: '3'
services:

  flask-web:
    build: .
    ports:
     - "5000:5000"

  redis:
    image: "redis:alpine"
2.5 运行 compose 项目
$ docker-compose up

此时访问本地 5000 端口,每次刷新页面,计数就会加 1。

3. 部署Django项目
3.1 编写Dockerfile
# 以python3.7.9为基础镜像
FROM python:3.7.9-buster

# 拷贝项目目录到容器的/app目录下
COPY . /app/

# 切换工作目录
WORKDIR /app 

# ENV PYTHONUNBUFFERED 1
# ENV DJANGO_SETTINGS_MODULE ems_project.settings
# ENV PYTHONPATH /app

# 执行指令  
RUN set -eux; \
        pip install --upgrade pip -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        pip install -r requirements.txt -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        rm -f requirements.txt

EXPOSE 9000

# 会被docker-compose覆盖
CMD ["uwsgi", "--ini", "uwsgi.ini"]

3.2 编写docker-compose.yml
# 指定版本信息
version: '3.8'

# 指定服务(启动的容器)
services:
   # 服务名: 项目根目录小写_当前指定的服务名_服务个数的序号
   # deploydjango_db_1
   db:
     # 指定镜像的名称
     # 如果本地有这个镜像, 会直接使用, 如果没有, 会去Docker hub中pull到本地
     image: mysql:5.7
     # 覆盖默认的CMD, 指定在运行容器时,(docker run), 需要运行的命令或者参数
     command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
     # 指定目录映射
     volumes:
       - mysql_db:/var/lib/mysql
       - /etc/timezone:/etc/timezone
       - /etc/localtime:/etc/localtime
     # 指定容器重启的策略
     restart: always
     # 指定环境变量
     environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: ems
    #  ports:
    #    - "13306:3306"

   web:
    depends_on:
      - db
    build: .     # 直接在docker-compose中打包镜像
    # image: ems  # 先打包镜像 再以ems为基础
    command: 
      - /bin/sh
      - -c
      - |
        python manage.py makemigrations 
        python manage.py migrate
        uwsgi --ini uwsgi.ini
    ports:
      - "8000:9000"   # 冒号后为 dockerfile中暴露的端口号 
    # links:
    #   - db

volumes:
    mysql_db: {}   # 需要创建数据卷  docker volume create --name mysql_db    

3.3 修改项目settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'ems',
        'USER':'root',
        'PASSWORD':'123456',
        'HOST':'db',
        'PORT':3306,
    }
}
3.4 uwsgi.ini文件
[uwsgi]
#uWSGI和nginx通信的port
http = 0.0.0.0:9000
# the base directory (full path)
chdir = /app
# Django's wsgi file
wsgi-file = ems_project/wsgi.py
# maximum number of worker processes
processes = 4
#thread numbers startched in each worker process
threads = 2
#monitor uwsgi status 通过该端口可以监控 uwsgi 的负载情况
# clear environment on exit
vacuum = true
pidfile = ./uwsgi.pid
#daemonize-run ,file-to-record-log
static-map =/static=./static
3.5 启动服务
1. 如果docker-compose中的 web使用的是image: ems 则需要先打包镜像
   - 以当前目录下的Dockerfile打包
   $ docker build -t ems .
   
2. docker-compose down

3. docker-compose up -d 后台启动

4. 打开浏览器访问即可
4. 使用nginx
4.1 编写nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        #server_name  localhost;
        # 使用uwsgi处理静态资源
        location / {
            #uwsgi_pass 101.133.225.166:8080;
            proxy_pass http://web:9000;
        }

        
    }
}
4.2 修改docker-compose
# 指定版本信息
version: '3'

# 指定服务(启动的容器)
services:
   # 服务名: 项目根目录小写_当前指定的服务名_服务个数的序号
   # deploydjango_db_1
   db:
     # 指定镜像的名称
     # 如果本地有这个镜像, 会直接使用, 如果没有, 会去Docker hub中pull到本地
     image: mysql:5.7
     # 覆盖默认的CMD, 指定在运行容器时,(docker run), 需要运行的命令或者参数
     command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
     # 指定目录映射
     volumes:
       - mysql_db:/var/lib/mysql
       - /etc/timezone:/etc/timezone
       - /etc/localtime:/etc/localtime
     # 指定容器重启的策略
     restart: always
     # 指定环境变量
     environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: ems
    #  ports:
    #    - "13306:3306"

   web:
    depends_on:
      - db
    build: .
    # image: ems
    command: 
      - /bin/sh
      - -c
      - |
        python manage.py makemigrations 
        python manage.py migrate
        uwsgi --ini uwsgi.ini
    # ports:
    #   - "9000:9000"
    # links:
    #   - db

   nginx:
      image: nginx:1.16-alpine
      ports:
        - "81:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
      depends_on:
        - web      

volumes:
    mysql_db: {}      
4.3 启动服务
$ docker-compose down && docker-compose up -d

打开浏览器通过81端口访问
5. nginx处理静态资源
  • 修改nginx配置文件
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        #server_name  localhost;
        # 使用uwsgi处理静态资源
        location / {
            #uwsgi_pass 101.133.225.166:8080;
            proxy_pass http://web:9000;
        }

        location /static {
            alias /app/static;
        }

    }
}
  • 添加.dockerignore文件
Dockerfile
docker-compose.yml
static
build.sh
start-server.sh
# 打包时 忽略static目录 不打包到镜像中 而是映射进去
  • docker-compose
   nginx:
      image: nginx:1.16-alpine
      ports:
        - "81:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
        - ./static:/app/static   # 映射静态资源
      depends_on:
        - web      
6.文件上传
# 指定版本信息
version: '3'

# 指定服务(启动的容器)
services:
   # 服务名: 项目根目录小写_当前指定的服务名_服务个数的序号
   # deploydjango_db_1
   db:
     # 指定镜像的名称
     # 如果本地有这个镜像, 会直接使用, 如果没有, 会去Docker hub中pull到本地
     image: mysql:5.7
     # 覆盖默认的CMD, 指定在运行容器时,(docker run), 需要运行的命令或者参数
     command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
     # 指定目录映射
     volumes:
       - mysql_db:/var/lib/mysql
       - /etc/timezone:/etc/timezone
       - /etc/localtime:/etc/localtime
     # 指定容器重启的策略
     restart: always
     # 指定环境变量
     environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: ems
    #  ports:
    #    - "13306:3306"

   web:
    depends_on:
      - db
    build: .
    # image: ems
    command: 
      - /bin/sh
      - -c
      - |
        python manage.py makemigrations 
        python manage.py migrate
        uwsgi --ini uwsgi.ini
    volumes:
      - ./static:/app/static      # 把静态资源目录映射到web容器中 和nginx共享 django项目直接把文件上传到static目录下即可
    # ports:
    #   - "9000:9000"
    # links:
    #   - db

   nginx:
      image: nginx:1.16-alpine
      ports:
        - "82:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
        - ./static:/app/static
      depends_on:
        - web      

volumes:
    mysql_db: {}      

十一、部署多个项目

一台服务器,部署多个项目,端口号都使用80,此时需要一个主nginx转发

1. 项目一
1.1 nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        #server_name  localhost;
        # 使用uwsgi处理静态资源
        location / {
            #uwsgi_pass 101.133.225.166:8080;
            proxy_pass http://web:9000;  # 这里写compose中服务的名字
        }

        location /static {
            alias /app/static;
        }

    }
}
1.2 docker-compose.yml
# 指定版本信息
version: '3'

networks:
  ems-network:
    external: true  # 对外
  foo: {} # 对内

# 指定服务(启动的容器)
services:
   # 服务名: 项目根目录小写_当前指定的服务名_服务个数的序号
   # deploydjango_db_1
   db:
     # 指定镜像的名称
     # 如果本地有这个镜像, 会直接使用, 如果没有, 会去Docker hub中pull到本地
     image: mysql:5.7
     # 覆盖默认的CMD, 指定在运行容器时,(docker run), 需要运行的命令或者参数
     command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
     networks:
       - foo
     # 指定目录映射
     volumes:
       - mysql_db:/var/lib/mysql
       - /etc/timezone:/etc/timezone
       - /etc/localtime:/etc/localtime
     # 指定容器重启的策略
     restart: always
     # 指定环境变量
     environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: ems
    #  ports:
    #    - "13306:3306"

   web:
    depends_on:
      - db
    build: .
    # image: ems
    networks:
      - foo
    command: 
      - /bin/sh
      - -c
      - |
        python manage.py makemigrations 
        python manage.py migrate
        uwsgi --ini uwsgi.ini
    # volumes:
    #   - ./static:/app/static    
    # ports:
    #   - "9000:9000"
    # links:
    #   - db

   nginx:
      image: nginx:1.16-alpine
      # 有了主nginx 子nginx不需要暴露端口
      # ports:
      #   - "81:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
        - ./static:/app/static
      depends_on:
        - web     
      networks:
        - foo
        - ems-network   

volumes:
    mysql_db: {}      

2. 项目二
2.1 nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        #server_name  localhost;
        # 使用uwsgi处理静态资源
        location / {
            #uwsgi_pass 101.133.225.166:8080;
            proxy_pass http://web2:9000;
        }

        location /static {
            alias /app/static;
        }

    }
}
2.2 docker-compose.yml
# 指定版本信息
version: '3'


networks:
  ems-network:
    external: true
  foo: {}

# 指定服务(启动的容器)
services:
   # 服务名: 项目根目录小写_当前指定的服务名_服务个数的序号
   # deploydjango_db_1
   db:
     # 指定镜像的名称
     # 如果本地有这个镜像, 会直接使用, 如果没有, 会去Docker hub中pull到本地
     image: mysql:5.7
     # 覆盖默认的CMD, 指定在运行容器时,(docker run), 需要运行的命令或者参数
     command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
     networks:
       - foo
     # 指定目录映射
     volumes:
       - mysql_db:/var/lib/mysql
       - /etc/timezone:/etc/timezone
       - /etc/localtime:/etc/localtime
     # 指定容器重启的策略
     restart: always
     # 指定环境变量
     environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: ems
    #  ports:
    #    - "13306:3306"

   web2:
    depends_on:
      - db
    build: .
    # image: ems
    command: 
      - /bin/sh
      - -c
      - |
        python manage.py makemigrations 
        python manage.py migrate
        uwsgi --ini uwsgi.ini
    networks:
      - foo
    volumes:
      - ./static:/app/static    
    # ports:
    #   - "9000:9000"
    # links:
    #   - db

   nginx2:
      image: nginx:1.16-alpine
       # 有了主nginx 子nginx不需要暴露端口
      # ports:
      #   - "82:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
        - ./static:/app/static
      depends_on:
        - web2   
      networks:
        - foo
        - ems-network   

volumes:
    mysql_db: {}      

3. Dockerfile
# 以python3.7.9为基础镜像
FROM python:3.7.9-buster

# 拷贝项目目录到容器的/app目录下
COPY . /app/

# 切换工作目录
WORKDIR /app 

# ENV PYTHONUNBUFFERED 1
# ENV DJANGO_SETTINGS_MODULE ems_project.settings
# ENV PYTHONPATH /app

# 执行指令  
RUN set -eux; \
        pip install --upgrade pip -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        pip install -r requirements.txt -i http://pypi.douban.com/simple  --trusted-host pypi.douban.com; \
        rm -f /tmp/requirements.txt

EXPOSE 9000

# 会被docker-compose覆盖
CMD ["uwsgi", "--ini", "uwsgi.ini"]

4. 主Nginx
4.1 nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen 80;
        server_name ems.bobby.org.cn;
        location / {
            proxy_pass http://nginx;
        }
    }
    server {
        listen 80;
        server_name ems2.bobby.org.cn;
        location / {
            proxy_pass http://nginx2;
        }
    }
}
4.2 docker-compose.yml
# 指定版本信息
version: '3'

networks:
  ems-network:
    external: true

# 指定服务(启动的容器)
services:
   nginx-master:
      image: nginx:1.16-alpine
      ports:
        - "88:80"
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf  
      networks:
        - ems-network

十二、Swarm mode

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值