Docker 详解

2023/10/26 Docker
目录

Docker是应用容器部署工具

# 1、Docker介绍

  • 先了解下虚拟机

学过Linux的应该知道,第一件事就是安装虚拟机,安装虚拟机是为了在windows上运行Linux系统,虚拟机相当于一个沙盒,在这个沙盒里安装的软件,不会影响到windows,也就是我们拥有了 一套环境隔离的操作系统。当我们不用时,只需要将虚拟机关闭,即可释放资源。

虚拟机是带环境安装的一种解决方案。

  • 虚拟机的缺点
  1. 资源占用多

虚拟机是一种模拟真实计算机环境的工具,它会占用一部分计算机的内存和硬盘空间。当虚拟机运行时,其他程序无法使用这些资源,即使虚拟机内部的应用程序实际只使用了1MB的内存,虚拟机仍需要几百MB的内存才能运行。

  1. 冗余步骤多

虚拟机是一个完整的操作系统环境,其内部的操作步骤往往无法省略或跳过,例如用户登录环节。

  1. 启动慢

启动虚拟机所需的时间与启动操作系统所需的时间相等,可能需要等待几分钟,应用程序才能真正运行。

  • 应用容器介绍

应用容器就相当于虚拟机,不过应用容器把虚拟机的缺点都解决了。也是一套环境隔离的操作系统。它具有启动快、资源占用少、体积小、易操作等等。相比虚拟机有很多优势。

  • 为什么都用应用容器部署

因为以往的部署成本高,而且部署难度大。可能有很多突然出现的环境问题,花费的人力太大。而应用容器部署很大程度上能解决这些问题,让部署简单化。

  • Docker应用容器

Docker是应用容器部署的典范,也是目前最为流行的应用部署方式。具有以下的一些应用场景:

  1. 提供了一次性部署环境。比如集成测试时,需要特定的环境,Docker就可以快速部署一个测试环境。
  2. 云服务。Docker能够很容易的进行动态扩容和缩容,并且随开随关,可以用于云服务部署。
  3. 微服务。以往部署微服务至少都要多台服务器,现在只需要一台服务器,通过Docker就可以部署多个微服务。实现了环境隔离。
  • 几个概念
  1. 镜像(Image):就像是软件安装包。
  2. docker-ce:docker社区版。用于运行容器。也就是我们需要先在Linux上安装的Docker软件。
  3. 容器(Container):镜像运行起来就是容器。一个容器就是一个环境隔离的虚拟机。

整理逻辑就是,我们在Linux上装了一个Docker软件,这个Docker软件可以安装镜像,安装完镜像,我们需要运行镜像,就得到一个容器。一个容器就是一台虚拟机。 这样一来,我们就可以在Linux上运行很多个虚拟机。也就是我们说的服务。一个前端项目运行在容器里,或者一个后端项目运行在容器里。 一台Linux服务器就可以运行n个项目,只要你的Linux服务器配置的足够高。简单理解就是,将一台Linux机子分成N个小Linux机子来运行项目

# 2、Docker安装

这里是Linux安装Docker,windows安装Docker比较简单,可以自己找网上教程。

如果觉得这样安装还麻烦的话,或者是新手使用Linux的话,可以安装一个宝塔面板 (opens new window),在宝塔商店中安装Docker。

  • 卸载之前安装过的旧版本

如果之前有安装过Docker的,需要先卸载清除干净

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine \
                  docker-ce
1
2
3
4
5
6
7
8
9
10
11
  • 更新软件包

用于在系统上安装软件包。

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
1

解释一下

  1. sudo yum install -y yum-utils: 这条命令使用yum(Yellowdog Updater, Modified)来安装yum-utils软件包。yum是一个包管理工具,类似于apt-get,它在Red Hat和相关Linux发行版上被广泛使用。-y选项是自动应答"yes"到所有提示,这样命令会在不等待用户确认的情况下继续执行。
  2. device-mapper-persistent-data: 这是一个软件包,包含Device Mapper Persistent Data模块,它用于在Linux内核中创建和管理持久卷。Device Mapper是Linux内核的一个功能,用于创建和管理磁盘设备映射。
  3. lvm2: 这是逻辑卷管理(Logical Volume Manager)的软件包,它提供了用于管理磁盘分区和卷组的工具。LVM允许您在不改变物理磁盘布局的情况下更灵活地管理和调整磁盘分区。

所以,这条命令的主要作用是在系统上安装三个软件包:yum-utils、device-mapper-persistent-data和lvm2。这些软件包提供了更高级的磁盘和分区管理功能,例如使用LVM来管理和调整磁盘分区的大小和可用空间。

  • 设置Docker仓库

设置Docker仓库,可从仓库安装和更新Docker。官方的可能比较慢,可以使用清华大学源地址。

# 官方源地址
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

# 清华大学源地址
sudo yum-config-manager \
    --add-repo \
    https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
1
2
3
4
5
6
7
8
9
  • Docker安装

docker-ce为社区免费版本。如果不需要docker-ce-clicontainerd.io,可以去掉。

sudo yum install -y docker-ce docker-ce-cli containerd.io
1

解释一下

docker-ce:这是一个 Docker 社区版(Community Edition)的软件包。它是一个开源的应用容器引擎,允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何 Linux 机器或者 Windows 机器上,也可以实现虚拟化。

docker-ce-cli:这是 Docker 社区版(Community Edition)的命令行接口。它允许你从命令行与 Docker 引擎交互。

containerd.io:这是一个开源的容器运行时工具,它允许开发者使用容器来运行、管理、打包他们的应用。Docker 和其他容器运行时工具使用的是容器运行时接口(CRI, Container Runtime Interface),而 containerd 则直接提供了一个更底层的 API。

  • Docker启动
sudo systemctl start docker
1
  • Docker安装验证

运行hello-world镜像来验证是否正确安装了Docker Engine-Community。

// 拉取镜像
sudo docker pull hello-world
// 执行hello-world
sudo docker run hello-world
1
2
3
4

如果显示了 Hello from Docker! 信息,则表示Docker安装成功。

# 3、配置镜像

Docker默认拉取镜像的仓库是Docker Hub (opens new window),国内访问Docker Hub速度很慢,可以配置国内镜像仓库。

这里配置阿里镜像仓库

阿里镜像加速

  • 登录阿里云获取镜像加速器地址

阿里镜像加速器

  • 修改配置文件

修改配置文件/etc/docker/daemon.json(没有时新建该文件)

vim /etc/docker/daemon.json
# 添加如下内容,可以自己替换。将阿里镜像加速器中地址粘贴过来
{
  "registry-mirrors": ["https://******.mirror.aliyuncs.com"]
}


# 也可以参考阿里镜像中的配置修改
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://******.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 重启Docker Daemon
systemctl daemon-reload
1

# 4、Docker架构概念

# 4.1、Docker 引擎

Docker 引擎(Docker Engine) 是 Docker 的核心组件,负责管理和运行容器。

Docker引擎由如下主要的组件构成:

  1. Docker 客户端(Docker Client):与 Docker Daemon 建立通信,发送请求给后者。
  2. Docker 守护进程(Docker Daemon):提供 Docker Server 的功能,可以接受 Docker Client 的请求。
  3. containerd:负责容器的创建和运行。
  4. runc:负责在容器中运行进程。

# 4.2、客户端 (Client)

  1. Docker是一个客户端-服务端(C/S)架构程序。
  2. Docker服务端提供了整套的 RESTful API
  3. Docker客户端通过命令与服务端进行交互,服务端完成所有工作,并返回结果。
  4. Docker客户端和Docker服务端可以运行在同一台机器上,也可以使用Docker客户端连接到远程Docker服务端,使用远程命令进行操作。

# 4.3、Docker Host

Docker Host是运行Docker容器的主机,可以是一个物理计算机、虚拟机或者云服务器。

# 4.4、镜像 (Image)

镜像是一个模板,就像是一个可执行的安装包。包含代码,运行时间,库,环境变量和配置文件等。

Docker可以把App文件打包成一个镜像,然后通过镜像就可以创建多个容器。就像一个App安装包,可以安装多次,比如像手机安装多个微信。

  • 多个App共用一套底层镜像(初始创建时)。
  • 单个App镜像可以创建多个容器。
  • 每个容器都是相互隔离的,互不影响。

# 4.5、容器 (Container)

Docker容器是镜像的运行实例。

  • Docker镜像和容器的关系,就像Java中的类和对象的关系一样。
  • Docker镜像是静态的模板,Docker容器是镜像的动态运行实例。
  • 容器可以被启动、开始、停止、删除。

# 4.6、镜像分层

Docker镜像支持扩展现有镜像,生成新的镜像。每生成一个镜像,就会在当前镜像的基础上,增加一层。这就是镜像分层

解释图中镜像分层

  1. 现在有一个基础镜像(Base Image),比如Debian
  2. 在基础镜像上安装emacs软件,就在基础镜像之上增加一层Image
  3. 再安装一个apache2软件,又在原来的基础之上新增一层Image

dockerfile代码如下

# 1.新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
FROM debian        
# 指定镜像作者信息        
MAINTAINER xygalxy 
# 2.安装 emacs 编辑器。
RUN apt-get update && apt-get install -y emacs        
# 3.安装 apache2。
RUN apt-get install -y apache2     
# 4.容器启动时运行 bash。        
CMD ["/bin/bash"]              
1
2
3
4
5
6
7
8
9
10

docker容器创建过程

docker容器创建完成,镜像分层情况

根据以上的镜像分层例子,对镜像分层应该已经有大致的了解,镜像分层特定总结:

1. 共享资源

采用镜像分层结构的最大好处就是共享资源。比如我构建了多个镜像,基础镜像都是Debian,那么 Docker Host 只需在磁盘上保存一份Debian基础镜像,并且内存中也只需加载一份Debian基础镜像,这样就可以为所有的容器服务了,而且每一个容器都可以共享基础镜像的资源。

2. Copy-on-Write

  • 镜像层只读。镜像一旦构建就不可修改,新数据将会放在最上层的容器层(Container)。
  • 容器层可写。如需修改现有镜像数据,会先将镜像的数据复制到容器层,修改后的数据直接保存再容器中,镜像层依然保持不变。
  • 文件从上往下读取。如果多层文件名称相同,读取顺序从上往下读取文件,匹配最上层文件。
  • 容器层+镜像层是一个文件系统。镜像的层数可能会有很多,所有的层数联合起来组成一个统一的文件系统。

只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write

文件系统深度说明

镜像的层数可能会有很多,所有的层数联合起来组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。

  • 添加文件: 在容器中创建文件时,新文件被添加到容器层中。
  • 读取文件: 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
  • 修改文件: 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
  • 删除文件: 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。

# 4.7、数据卷 (Volume)

Docker运行的容器就是一个简版的操作系统。一旦容器删除了,也就是卸载了操作系统(通俗就是卸载了软件),容器中的数据也就丢失了。为了防止数据丢失,Docker引入了数据卷的概念。数据卷也就是将容器中的数据持久化保存到宿主机,这样即使容器删除了,宿主机中的数据卷数据依然存在。

数据卷的特性

  • 数据卷可以在容器之间共享和重用。
  • 对数据卷的修改会立马生效。
  • 数据卷中的更改不会包含在镜像的更新中。
  • 数据卷的生命周期一直持续到没有容器使用它为止。

# 4.8、注册中心 (Registry)

DockerRegistry是用来保存镜像的,Registry分为公有仓库和私有仓库。Docker公司默认的RegistryDocker Hub (opens new window)

Registry理解就是类似GitHub,GitHub是保存代码的,Registry是保存镜像的。

以GitHub来解释一下,GitHub就类似一个Registry。GitHub下可以创建多个仓库,也就是我们说的项目,这个就是Docker的Repository,用来存放一个软件镜像。而标签就像GitHub中的分支,默认为master分支,而Docker默认为latest。并且GitHub项目可以设置为公开和私有,也就是Docker的公开仓库和私有仓库。

# 5、镜像命令

# 5.1、查看镜像

# tag默认latest
docker images [OPTIONS] [REPOSITORY[:TAG]]

# OPTIONS如下:
-a                  # 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层)
--digests           # 显示镜像的摘要信息
-f                  # 显示满足条件的镜像
--format            # 指定返回值的模板文件
--no-trunc          # 显示完整的镜像信息
-q                  # 只显示镜像ID。

# 常用命令
docker images                             # 列出本地所有镜像
docker images -a                          # 列出本地所有镜像(含中间映像层)
docker images -qa                         # qa可一起使用
docker images ubuntu:18.04                # 列出ubuntu:18.04镜像
docker images --digests ubuntu:18.04      # 列出ubuntu:18.04镜像的摘要信息
docker images --no-trunc ubuntu:18.04     # 列出完整信息
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"   # 列出并指定格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 5.2、搜索镜像

# tag默认latest
docker search [OPTIONS] [REPOSITORY[:TAG]]

# OPTIONS如下:
--automated             # 只列出 automated build类型的镜像;
--no-trunc              # 显示完整的镜像描述;
-s                      # 列出收藏数不小于指定值的镜像。

# 常用命令
docker search mysql                       # 搜索mysql镜像
docker search --no-trunc mysql            # 搜索mysql镜像,显示完整的镜像描述
docker search -s 10 mysql                 # 搜索mysql镜像,列出收藏数不小于10的镜像
docker search --automated mysql           # 搜索mysql镜像,只列出 automated build类型的镜像
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5.3、拉取镜像

# tag默认latest
docker pull [OPTIONS] NAME[:TAG]

# OPTIONS如下:
-a                        # 拉取所有 tag 镜像
--disable-content-trust   # 忽略镜像的校验,默认开启

# 常用命令
docker pull java          # 拉取java镜像,默认latest
docker pull mysql:5.7     # 拉取mysql:5.7镜像
1
2
3
4
5
6
7
8
9
10

# 5.4、删除镜像

# 根据镜像ID删除镜像
docker rmi [OPTIONS] [IMAGE_ID...]
# 根据名字删除镜像
docker rmi 镜像名[:Tag]	

# OPTIONS如下:
-f                # 强制删除;
--no-prune        # 不移除该镜像的过程镜像,默认移除

# 常用命令
docker rmi 0428d727780b                   # 删除镜像ID为0428d727780b的镜像
docker rmi -f 0428d727780b                # 强制删除镜像ID为0428d727780b的镜像
docker rmi 0428d727780b 0428d727780c      # 删除多个镜像

docker rmi mysql	                      # 根据名字删除mysql镜像(tag为latest)
docker rmi mysql:5.7                      # 根据名字删除mysql镜像(tag为5.7)

# 全部删除,因为 `docker images -q` 指罗列出当前镜像的 `image ID`
docker rmi -f $(docker images -qa)        # 强制删除全部镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注意

如果通过某个镜像创建了容器,则该镜像无法删除。

解决办法:先删除镜像中的容器,再删除该镜像

# 5.5、镜像构建

建议先将容器命令看完再来看镜像构建

Docker支持自定义镜像构建,外部的镜像可能不太能满足我们的需求,这时我们可以通过自定义镜像构建来满足我们的需求。另外一种就是我们自己的项目,希望也能构建为一个镜像,方便我们快速部署。

Docker镜像构建提供了两种方式:

  • docker commit: 从容器创建一个新的镜像。
  • docker build: 配合Dockerfile文件创建镜像。

查看构建历史

docker history 镜像名称:标签|ID
1
  • docker commit

语法

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

# OPTIONS如下:
-a  # 提交的镜像作者;
-c  # 使用 Dockerfile 指令来创建镜像;
-m  # 提交时的说明文字;
-p  # 在 commit 时,将容器暂停。
1
2
3
4
5
6
7

目标需求:我们通过基础的镜像centos7,在该镜像上安装JDKTomcat,作为我们的新镜像。

# 拉取镜像
docker pull centos:7

# 创建容器
docker run -di --name centos7 centos:7

# 将JDK和Tomcat安装压缩包到拷贝到容器中
docker cp jdk-8u111-linux-x64.tar.gz centos7:/root
docker cp apache-tomcat-8.5.27.tar.gz centos7:/root

# 进入容器,并创建目录,将压缩包解压到目录中
docker exec -it centos7 /bin/bash
cd /root
mkdir -p /usr/local/java
mkdir -p /usr/local/tomcat

tar -zxvf jdk-8u111-linux-x64.tar.gz -C /usr/local/java/
tar -zxvf apache-tomcat-8.5.27.tar.gz -C /usr/local/tomcat/

# 配置JDK环境
vi /etc/profile

# 在文件profile最后新增如下内容
export JAVA_HOME=/usr/local/java/jdk1.8.0_111/
export PATH=$PATH:$JAVA_HOME/bin

# 重新加载环境变量文件
source /etc/profile

# 测试JDK是否配置成功
java -version

# 将安装压缩包删除
rm -rf jdk-8u111-linux-x64.tar.gz apache-tomcat-8.5.27.tar.gz 

# 退出容器
exit

# 构建镜像
docker commit -a="xygalaxy" -m="jdk and tomcat" centos7 mycentos:7

# 使用构建的新镜像创建容器
docker run -d --name mycentos7 -p 8080:8080 mycentos:7

# 进入容器重新加载配置文件
docker exec -it mycentos7 /bin/bash
source /etc/profile

# 测试JDK环境是否已存在
java -version

# 启动Tomcat
/usr/local/tomcat/apache-tomcat-8.5.27/bin/startup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

访问http://{ip}:8080,如果有Tomcat界面,则表示环境配置成功。

  • docker build

先了解下下一节Dockerfile的内容,再回来看这个命令。

语法

# 使用当前目录的 Dockerfile 创建镜像
docker build -t mycentos:7 .

# 通过 -f Dockerfile 文件的位置创建镜像
docker build -f /home/ruoyi/docker/Dockerfile -t mycentos:7 .

# 参数说明
-f         # 指定要使用的 Dockerfile 路径;
--tag, -t  # 镜像的名字及标签,可以在一次构建中为一个镜像设置多个标签。

1
2
3
4
5
6
7
8
9
10

目标需求:我们通过基础的镜像centos7,在该镜像上安装JDKTomcat,作为我们的新镜像。

# 创建Dockerfile文件
mkdir -p /usr/local/`dockerfile`

# 编写Dockerfile命令,参考Dockerfile中文件

# 构建镜像
docker build -f /home/ruoyi/docker/Dockerfile -t mycentos:test .

# 启动容器
docker run -d --name mycentos -p 8080:8080 mycentos:test

# 进入容器
docker exec -it mycentos7 /bin/bash

# 查看JDK环境
java -version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5.6、 Dockerfile

自定义构建镜像时,需要编写一个Dockerfile文件,文件包含构建指令,指定了Docker如何来构建镜像,常用命令如下,也可参考官方文档。 官方文档 (opens new window)

  • Dockerfile常用命令说明
FROM	       # 指定基础镜像,用于后续的指令构建。
MAINTAINER	   # 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
LABEL	       # 添加镜像的元数据,使用键值对的形式。
RUN	           # 在构建过程中在镜像中执行命令。
CMD	           # 指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT	   # 设置容器创建时的主要命令。(不可被覆盖)
EXPOSE	       # 声明容器运行时监听的特定网络端口。
ENV	           # 在容器内部设置环境变量。
ADD	           # 将文件、目录或远程URL复制到镜像中。
COPY	       # 将文件或目录复制到镜像中。
VOLUME	       # 为容器创建挂载点或声明卷。
WORKDIR	       # 设置后续指令的工作目录。
USER	       # 指定后续指令的用户上下文。
ARG	           # 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
ONBUILD	       # 当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL	   # 设置发送给容器以退出的系统调用信号。
HEALTHCHECK	   # 定义周期性检查容器健康状态的命令。
SHELL	       # 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 编写Dockerfile文件
# 指明构建的新镜像是来自于`centos:7`基础镜像
FROM centos:7
# 通过镜像标签声明了作者信息
LABEL maintainer="ruoyi.vip"

# 设置工作目录
WORKDIR /usr/local
# 新镜像构建成功以后创建指定目录
RUN mkdir -p /usr/local/java && mkdir -p /usr/local/tomcat
# 拷贝文件到镜像中并解压
ADD jdk-8u111-linux-x64.tar.gz /usr/local/java
ADD apache-tomcat-8.5.27.tar.gz /usr/local/tomcat
# 暴露容器运行时的 8080 监听端口给外部
EXPOSE 8080
# 设置容器内 JAVA_HOME 环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_111
ENV PATH $PATH:$JAVA_HOME/bin
# 启动容器时启动 tomcat
CMD ["/usr/local/tomcat/apache-tomcat-8.5.27/bin/catalina.sh", "run"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 6、容器命令

# 6.1、查看容器

docker ps			# 显示正在运行的容器
docker ps -a		# 显示所有容器
docker ps -l		# 显示最近的一个容器
docker ps -n2		# 显示最近创建的两个容器
docker ps -q		# 显示容器ID

docker top 容器名			# 查看容器里面的进程
docker stats 容器名			# 查看容器资源使用情况(不指定容器,会查看所有容器的使用情况)
docker inspect 容器名		# 查看容器元数据
1
2
3
4
5
6
7
8
9

# 6.2、查看日志

docker logs [OPTIONS] 容器名

# OPTIONS如下:
-f		                  # 动态查看 
-t		                  # 显示时间戳 
--tail 20	              # 显示最近的20行
--since 30m               # 显示最近30分钟的日志
--since="2018-02-08"      # 指定时间之后日志
--since="2018-02-08T13:23:37" --until "2018-02-09T12:23:37"  # 查看某段时间日志
1
2
3
4
5
6
7
8
9

# 6.3、创建容器并启动

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

# OPTIONS如下:
-i     # 表示运行容器;
-t     # 表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端;
--name # 为创建的容器命名;
-v     # 表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个 -v 做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上;
-d     # 在 run 后面加上 -d 参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加 -i -t 两个参数,创建容器后就会自动进容器里);
-p     # 表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个 -p 做多个端口映射。
-P     # 随机使用宿主机的可用端口与容器内暴露的端口映射。
--privileged    # 授予此容器扩展特权,也就是开启特权模式;这种模式下容器对docker宿主机拥有root访问权限,允许我们以其宿主机具有(几乎)所有能力来运行容器,包括一些内核特性和设备访问,慎用
--env  # 设置环境变量

# 常用命令
# 启动centos容器,并进入容器的/bin/bash
docker run -it centos /bin/bash    

# 创建容器后台运行(守护线程运行),命名为mycentos,并映射端口为:8080:80,其中8080为宿主机IP,80为容器IP。镜像为centos,默认tag为latest。
docker run -d --name mycentos -p 8080:80 centos  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 6.4、挂载目录

挂载目录就是将宿主机的目录挂载到容器中,在容器中操作目录,那么宿主机的目录也会跟着改变。我们知道当容器删除时,容器的内容会都删除。所以我们需要进行数据持久化。所以就需要对容器的目录进行挂载。如果多个容器挂载了同一个目录,那么宿主机的目录会变成多个容器共享。删除了其中一个容器,其他容器不会被影响。

目录挂载分为:匿名挂载具名挂载指定路径挂载

# 查看 volume 数据卷信息
docker volume ls

# 挂载目录,将宿主机目录/home/ruoyi/data挂载到容器/usr/local/data,当容器删除时,容器的内容会都删除,但是宿主机的内容不会删除。
docker run -d -v /home/ruoyi/data:/usr/local/data --name centos7-01 centos:7

# 多目录挂载
docker run -d -v /宿主机目录:/容器目录 -v /宿主机目录2:/容器目录2 镜像名

# 匿名挂载:只需要写容器目录即可,容器外对应的目录会在/var/lib/docker/volumes中生成。
docker run -d -v /usr/local/data --name centos7-02 centos:7

# 具名挂载:具名挂载就是给数据卷起了个名字,容器外对应的目录会在/var/lib/docker/volume中生成。
docker run -d -v docker_centos_data:/usr/local/data --name centos7-03 centos:7

# 指定路径挂载:是在宿主机上创建一个目录,然后将该目录挂载到容器中。
docker run -d -v /mydata/docker_centos/data:/usr/local/data --name centos7-01 centos:7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意

目录挂载操作可能会出现权限不足的提示。这是因为CentOS7中的安全模块SELinux把权限禁掉了,在docker run时通过--privileged=true给该容器加权限来解决挂载的目录没有权限的问题。

# 6.5、启动/停止/删除容器

docker start 容器名			     # 启动容器
docker restart 容器名		     # 重启容器
docker stop 容器ID或容器名       # 停止容器
docker kill 容器名			     # 强制停止容器
docker rm 容器ID或容器名		 # 删除容器
docker rm -f 容器名			     # 强制删除容器,可以删除运行中的容器
docker rm -v 容器名			     # 删除容器的同时也删除与之关联的volume

docker pause 容器名			     # 暂停容器
docker unpause 容器名		     # 取消暂停容器
1
2
3
4
5
6
7
8
9
10

# 6.6、进入容器

docker exec -it 容器名称|容器ID /bin/bash	#进入容器,并分配一个新的终端
1

# 6.7、退出当前容器

#退出容器
exit						
1
2

# 6.8、文件拷贝

docker cp /etc/hosts 容器名:/opt		# 拷贝宿主机的hosts文件到容器的/opt目录下
docker cp 容器名:/opt/a.sh /tmp		    # 拷贝容器的a.sh文件到宿主机的/tmp路径下
1
2

# 6.9、查看容器信息

docker inspect 容器名称|容器ID

docker inspect -f '{{.HostConfig.LogConfig}}' 容器名	                   # 查看容器日志策略
docker inspect --format "{{ .State.Pid }}" 容器名		                   # 查看容器在宿主机对应的PID
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称|容器ID   # 查看容器 IP 地址
1
2
3
4
5

# 7、应用部署案例

  • Mysql部署并将数据目录进行挂载
# 拉取镜像
docker pull mysql:5.7

# 宿主机创建挂载目录
mkdir -p /home/mysql/data /home/mysql/logs /home/mysql/conf

# 创建容器并映射挂载目录,\代表换行了,一行执行就行
docker run -p 3306:3306 --name mysql \
-v /home/mysql/conf:/etc/mysql/conf.d \
-v /home/mysql/logs:/logs  \
-v /home/mysql/data:/var/lib/mysql \ 
-e MYSQL_ROOT_PASSWORD=password \
-d mysql:5.7
1
2
3
4
5
6
7
8
9
10
11
12
13
  • Redis部署
# 拉取镜像,不指定tag,默认拉取最新版latest
docker pull redis

# 创建容器并运行,MODE=standalone表示单机启动
docker run -di --env MODE=standalone --name redis -p 6379:6379 redis
1
2
3
4
5

# 8、镜像仓库

  • 镜像仓库就类似于代码仓库GitHub一样,有兴趣可以去了解一下。企业项目是一定会用到的,每个企业也会有自己的镜像仓库。

  • DockerHub官网 (opens new window),可以注册一个账号,将自己构建的镜像推送到GitHub建立的镜像仓库。然后再拉取一下刚刚推送的镜像是否成功。

  • 国内也有很多这类仓库,这里推荐阿里容器镜像服务 (opens new window),个人版免费并不限时长,可以自己尝试一下。

# 9、Docker Compose ✨

痛点

Dockerfile可以很容易帮助我们构建一个自定义的镜像并启动运行。但是如果我是集群服务,我需要启动多个容器,我需要一个个的启动,是不是很麻烦。或者像微服务一样,我们可能有很多不同的服务模块,如果手动一个个的去构建,那将是很费时间和精力的事,也容器出错。这个时候我们就需要用到 Docker Compose (opens new window)

  • Docker Compose是什么?

Docker ComposeDocker官方的开源项目,负责实现对Docker容器集群的快速编排。简单理解就是它能帮助我们一下子启动多个容器。

  • Docker Compose使用步骤
  1. 定义Dockerfile
  2. 定义docker-compose.yml
  3. 运行docker-compose up命令创建并启动所有服务

# 9.1、安装Docker Compose

  • 下载
curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 因为Docker Compose存放在GitHub,可能不太稳定。可以通过DaoCloud加速下载
curl -L https://get.daocloud.io/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
1
2
3
4
  • 授权
# 将可执行权限应用于该二进制文件
sudo chmod +x /usr/local/bin/docker-compose
1
2
  • 测试安装是否成功
docker-compose --version
1
  • 卸载命令
rm /usr/local/bin/docker-compose
1

# 9.2、docker-compose.yml详解

docker-compose通过yaml文件来配置和管理容器。通过一个简单案例看看docker-compose是如何创建容器?

案例:创建并启动一个nginx项目

  • 创建一个docker-compose.yml文件
mkdir /root/docker-compose.yml
1
  • 编辑docker-compose.yml文件
vi /root/docker-compose.yml
1
  • docker-compose.yml添加以下内容
# 描述 Compose 文件的版本信息
version: "3.8"

# 定义服务,可以多个
services:
  nginx: # 服务名称
    image: nginx # 创建容器时所需的镜像
    container_name: mynginx # 容器名称,默认为"工程名称_服务条目名称_序号"
    ports: # 宿主机与容器的端口映射关系
      - "80:80" # 左边宿主机端口:右边容器端口
    networks: # 配置容器连接的网络,引用顶级 networks 下的条目
      - nginx-net

# 定义网络,可以多个。如果不声明,默认会创建一个网络名称为"工程名称_default"的 bridge 网络
networks:
  nginx-net: # 一个具体网络的条目名称
    name: nginx-net # 网络名称,默认为"工程名称_网络条目名称"
    driver: bridge # 网络模式,默认为 bridge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 启动所有服务
# 前台启动
docker-compose up

# 后台启动
docker-compose up -d
1
2
3
4
5

浏览器访问:http://{ip}/ 显示nginx首页

整个案例流程下来就类似启动容器命令,这样不是更慢吗?这是单个容器启动确实容器命令直接启动比较快,但我如果是多个容器启动,那就docker-compose更方便了。

docker run -d --name mynginx -p 80:80 nginx
1

配置参数详细解析

  • version: docker-compose的版本信息,可参考:docker-compose版本官方文档 (opens new window)

  • services:用来定义服务,可以多个,每个服务中定义了创建容器时所需的镜像、参数、依赖等,就像将命令行参数传递给docker run一样。同样,网络和数据卷的定义也是一样的。

docker run -di --name mysql8 -p 3306:3306 -v /mydata/docker_mysql/conf:/etc/mysql/conf.d -v /mydata/docker_mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=1234 mysql:8
1

等价于docker-compose.yml

version: "3.8"
# 定义服务,可以多个
services:
  mysql: # 服务名称
    image: mysql:8 # 创建容器时所需的镜像
    container_name: mysql8 # 容器名称,默认为"工程名称_服务条目名称_序号"
    ports: # 宿主机与容器的端口映射关系
      - "3306:3306" # 左边宿主机端口:右边容器端口
    environment: # 创建容器时所需的环境变量
      MYSQL_ROOT_PASSWORD: 1234
    volumes:
      - "/mydata/docker_mysql/conf:/etc/mysql/conf.d"
      - "/mydata/docker_mysql/data:/var/lib/mysql"
1
2
3
4
5
6
7
8
9
10
11
12
13
  • image:指定创建容器时所需的镜像名称标签或者镜像ID。如果镜像在本地不存在,会去远程拉取。
services:
  web:
    image: hello-world
1
2
3
  • build:除了可以基于指定的镜像构建容器,还可以基于Dockerfile文件构建,在使用up命令时会执行构建任务。
  • context:该选项可以是Dockerfile文件的绝对/相对路径,也可以是远程Git仓库的URL,当提供的值是相对路径时,相对当前docker-compose.yml文件所在目录。
build:
  context: . # 相对当前 docker-compose.yml 文件所在目录,基于名称为 Dockerfile 的文件构建镜像
1
2
  • dockerfile:一般情况下,默认都基于文件名叫Dockerfile的文件构建镜像,当然也可以是自定义的文件名,使用dockerfile声明,不过这个选项只能声明文件名,文件所在路径还是要通过centext来声明。
build:
  context: . # 相对当前 docker-compose.yml 文件所在目录
  dockerfile: Dockerfile-alternate # 基于名称为 Dockerfile-alternate 的文件构建镜像
1
2
3
  • container_name:创建的容器默认生成的名称格式为:工程名称_服务条目名称_序号。如果要使用自定义名称,使用container_name声明。
services:
  mycentos:
    build: .
    container_name: mycentos7 # 容器名称,默认为"工程名称_服务条目名称_序号"
1
2
3
4
  • depends_on:depends_on是用来解决容器依赖、启动先后问题的配置项。容器按依赖的顺序启动。
version: "3.8"

services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: mysql
1
2
3
4
5
6
7
8
9
10
11
12

容器会先启动db和redis两个服务,最后才启动web服务

  • ports:容器对外暴露的端口,可指定多个,格式:左边宿主机端口:右边容器端口。
ports:
  - "80:80"
  - "8080:8080"
1
2
3
  • expose:容器暴露的端口不映射到宿主机,只允许能被连接的服务访问。
expose:
  - "80"
  - "8080"
1
2
3
  • restart:容器重启策略,简单的理解就是Docker重启以后容器要不要一起启动

  • no:默认的重启策略,在任何情况下都不会重启容器;
  • on-failure:容器非正常退出时,比如退出状态为非0(异常退出),才会重启容器;
  • always:容器总是重新启动,即使容器被手动停止了,当Docker重启时容器也还是会一起启动;
  • unless-stopped:容器总是重新启动,除非容器被停止(手动或其他方式),那么Docker重启时容器则不会启动。
services:
  nginx:
    image: nginx
    container_name: mynginx
    ports:
      - "80:80"
    restart: always
1
2
3
4
5
6
7
  • environment:添加环境变量。可以使用数组也可以使用字典。布尔相关的值(true、false、yes、no)都需要用引号括起来,以确保 YML 解析器不会将它们转换为真或假。
environment:
  RUOYI_ENV: development
  SHOW: 'true'
  SESSION_SECRET:

# 或者格式

environment:
  - RUOYI_ENV=development
  - SHOW=true
  - SESSION_SECRET
1
2
3
4
5
6
7
8
9
10
11
  • env_file:从文件中获取环境变量,可以指定一个或多个文件,其优先级低于environment指定的环境变量。env 文件中的每一行需采用键=值格式。以#开头的行会被视为注释并被忽略。空行也会被忽略。
env_file:
  - /opt/runtime_opts.env # 绝对路径
  - ./common.env # 相对路径,相对当前 docker-compose.yml 文件所在目录
  - ./apps/web.env # 相对路径,相对当前 docker-compose.yml 文件所在目录
1
2
3
4
  • command:覆盖容器启动后默认执行的命令。
command: echo "helloworld"
# 或者
command: ["echo", "helloworld"]
1
2
3
  • volumes:数据卷,用于实现目录挂载,支持指定目录挂载、匿名挂载、具名挂载。

  • 指定目录挂载的格式为:左边宿主机目录:右边容器目录,或者左边宿主机目录:右边容器目录:读写权限;
  • 匿名挂载格式为:容器目录即可,或者容器目录即可:读写权限;
  • 具名挂载格式为:数据卷条目名称:容器目录,或者数据卷条目名称:容器目录:读写权限。
# 描述 Compose 文件的版本信息
version: "3.8"

# 定义服务,可以多个
services:
  mysql: # 服务名称
    image: mysql:8 # 创建容器时所需的镜像
    container_name: mysql8 # 容器名称,默认为"工程名称_服务条目名称_序号"
    ports: # 宿主机与容器的端口映射关系
      - "3306:3306" # 左边宿主机端口:右边容器端口
    environment: # 创建容器时所需的环境变量
      MYSQL_ROOT_PASSWORD: 1234
    volumes:
      # 绝对路径
      - "/mydata/docker_mysql/data:/var/lib/mysql"
      # 相对路径,相对当前 docker-compose.yml 文件所在目录
      - “./conf:/etc/mysql/conf.d“
      # 匿名挂载,匿名挂载只需要写容器目录即可,容器外对应的目录会在 /var/lib/docker/volume 中生成
      - "/var/lib/mysql"
      # 具名挂载,就是给数据卷起了个名字,容器外对应的目录会在 /var/lib/docker/volume 中生成
      - "mysql-data-volume:/var/lib/mysql"

# 定义数据卷,可以多个
volumes:
  mysql-data-volume: # 一个具体数据卷的条目名称
    name: mysql-data-volume # 数据卷名称,默认为"工程名称_数据卷条目名称"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • network_mode:网络模式
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
1
2
3
4
5
  • networks:配置容器连接的网络,引用顶级 networks 下的条目。
# 定义服务,可以多个
services:
  nginx: # 服务名称
    networks: # 配置容器连接的网络,引用顶级 networks 下的条目
      - nginx-net # 一个具体网络的条目名称

# 定义网络,可以多个。如果不声明,默认会创建一个网络名称为"工程名称_default"的 bridge 网络
networks:
  nginx-net: # 一个具体网络的条目名称
    name: nginx-net # 网络名称,默认为"工程名称_网络条目名称"
    driver: bridge # 网络模式,默认为 bridge
1
2
3
4
5
6
7
8
9
10
11
  • aliases:网络上此服务的别名。同一网络上的其他容器可以使用服务名或此别名连接到服务容器。同一服务在不同的网络上可以具有不同的别名。
# 定义服务,可以多个
services:
  nginx: # 服务名称
    networks: # 配置容器连接的网络,引用顶级 networks 下的条目
      nginx-net: # 一个具体网络的条目名称
        aliases: # 服务别名,可以多个
          - nginx1 # 同一网络上的其他容器可以使用服务名或此别名连接到服务容器

# 定义网络,可以多个。如果不声明,默认会创建一个网络名称为"工程名称_default"的 bridge 网络
networks:
  nginx-net: # 一个具体网络的条目名称
    name: nginx-net # 网络名称,默认为"工程名称_网络条目名称"
    driver: bridge # 网络模式,默认为 bridge
1
2
3
4
5
6
7
8
9
10
11
12
13

# 9.3、docker-compose常用命令

语法

docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]

# 参数说明
-f,--file         # 指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定,指定多个 yml;
-p, --project-name # 指定工程名称,默认使用 docker-compose.yml 文件所在目录的名称;
-v                 # 打印版本并退出;
--log-level        # 定义日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)。
1
2
3
4
5
6
7

docker-compose命令解析

  • help:查看帮助。
docker-compose -help
1
  • config:验证docker-compose.yml文件。当配置正确时,不输出任何内容,当配置错误时,输出错误信息。
docker-compose config -q
1
  • pull:拉取服务依赖的镜像。
# 拉取工程中所有服务依赖的镜像
docker-compose pull
# 拉取工程中 nginx 服务依赖的镜像
docker-compose pull nginx
# 拉取镜像过程中不打印拉取进度信息
docker-compose pull -q
1
2
3
4
5
6
  • up:建并启动所有服务的容器。
# 前台启动
docker-compose up
# 后台启动
docker-compose up -d
# -f 指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定,指定多个 yml
docker-compose -f docker-compose.yml up -d 
1
2
3
4
5
6
  • logs:查看服务容器的输出日志
# 输出日志,不同的服务输出使用不同的颜色来区分
docker-compose logs
# 跟踪日志输出
docker-compose logs -f
# 关闭颜色
docker-compose logs --no-color
1
2
3
4
5
6
  • ps:列出工程中所有服务的容器。
# 列出工程中所有服务的容器
docker-compose ps
# 列出工程中指定服务的容器
docker-compose ps nginx
1
2
3
4
  • run:指定服务容器上执行一个命令。
# 在工程中指定服务的容器上执行 echo "helloworld"
docker-compose run nginx echo "helloworld"
1
2
  • exec:进入服务容器。
# 进入工程中指定服务的容器
docker-compose exec nginx bash
# 当一个服务拥有多个容器时,可通过 --index 参数进入到该服务下的任何容器
docker-compose exec --index=1 nginx bash
1
2
3
4
  • pause:暂停服务容器。
# 暂停工程中所有服务的容器
docker-compose pause
# 暂停工程中指定服务的容器
docker-compose pause nginx

1
2
3
4
5
  • unpause:恢复服务容器。
# 恢复工程中所有服务的容器
docker-compose unpause
# 恢复工程中指定服务的容器
docker-compose unpause nginx
1
2
3
4
  • restart:重启服务容器。
# 重启工程中所有服务的容器
docker-compose restart
# 重启工程中指定服务的容器
docker-compose restart nginx
1
2
3
4
  • start:启动服务容器。
# 启动工程中所有服务的容器
docker-compose start
# 启动工程中指定服务的容器
docker-compose start nginx
1
2
3
4
  • stop:停止服务容器。
# 停止工程中所有服务的容器
docker-compose stop
# 停止工程中指定服务的容器
docker-compose stop nginx
1
2
3
4
  • kill:停止指定服务的容器。
# 通过发送 SIGKILL 信号停止工程中指定服务的容器
docker-compose kill nginx
1
2
  • rm:删除服务(停止状态)容器。
# 删除所有(停止状态)服务的容器
docker-compose rm
# 先停止所有服务的容器,再删除所有服务的容器
docker-compose rm -s
# 不询问是否删除,直接删除
docker-compose rm -f
# 删除服务容器挂载的数据卷
docker-compose rm -v
# 删除工程中指定服务的容器
docker-compose rm -sv nginx
1
2
3
4
5
6
7
8
9
10
  • down:停止并删除所有服务的容器、网络、镜像、数据卷。
# 停止并删除工程中所有服务的容器、网络
docker-compose stop
# 停止并删除工程中所有服务的容器、网络、镜像
docker-compose down --rmi all
# 停止并删除工程中所有服务的容器、网络、数据卷
docker-compose down -v
1
2
3
4
5
6
  • images:打印服务容器所对应的镜像。
# 打印所有服务的容器所对应的镜像
docker-compose images
# 打印指定服务的容器所对应的镜像
docker-compose images nginx
1
2
3
4
  • port:印指定服务容器的某个端口所映射的宿主机端口。
docker-compose port nginx 80
1
  • top:显示正在运行的进程。
# 显示工程中所有服务的容器正在运行的进程
docker-compose top
# 显示工程中指定服务的容器正在运行的进程
docker-compose top nginx
1
2
3
4

# 10、Docker管理工具

Docker命令是必须要掌握的,但是操作命令的效率比较低,并且查看效果不太好,所以可以使用一些Docker可视化管理工具。下面推荐几款,如何选择看个人,萝卜青菜各有所爱。

  • Portainer

Portainer是一款开源的容器管理平台,它提供了一个直观易用的Web界面,帮助用户管理Docker容器集群、镜像、卷等资源。Portainer官方地址 (opens new window),可参考汉化教程Portainer 基本功能介绍 (opens new window)

  • DockStation

DockStation是一款基于Docker容器的开源工具,可以帮助用户轻松管理和部署应用程序。它提供了一个友好的图形界面,使用户能够以可视化的方式创建和管理容器和镜像。

  • DockerUI

DockerUI是一个易用且轻量化的 Docker 管理工具,透过 Web 界面的操作,更方便对于 Docker 指令不熟悉的用户更快进入 Docker 的世界。DockerUI项目地址 (opens new window)

  • 宝塔面板 Docker

宝塔面板Docker面板,是宝塔面板的扩展。对于个人项目来说,使用宝塔面板Docker面板可以快速部署网站,并且可以管理网站的Docker环境。如果是企业中自己用的话,会有版权问题,建议还是个人项目用比较好。如果公司有企业版的话,可以考虑使用。宝塔官网 (opens new window)