Docker:应用容器引擎
一、 Docker简介
什么是Docker
Docker 是基于Go语言实现的开源容器项目。利用操作系统本身已有的机制和特性,可以实现远超传统虚拟机的轻量级虚拟化(通俗解释:Docker内嵌极小型系统,例如Linux只有5M多,windows也是)。它是内核级的虚拟化。期望达到使项目运行环境“一次封装,到处运行的目的”。
在Docker里面可以设置使用Windows还是Linux系统,默认是用Linux系统,基于Ubuntu的,只有5M多,包含了最基本功能。利用docker创建的运行环境叫做docker容器,容器是通过docker镜像创建的,docker镜像文件可以放在私有仓库中也可以放在公有仓库中。
官网地址:https://www.docker.com
二、Docker架构(重点)
1 Docker daemon(Docker守护进程)
Docker daemon是一个运行在宿主机(DOCKER_HOST)的后台进程。我们可通过它让Docker客户端与Docker通信
2 Client(Docker客户端)
Docker客户端是Docker的用户界面,它可以接受用户命令和配置标识,并与Docker daemon通信。图中,docker build等都是Docker的相关命令。
3 Images(Docker镜像)
Docker镜像是一个只读模板,它包含创建Docker容器的说明。和虚拟机中快照是类似的。在虚拟机中根据快照克隆一台虚拟机中。在Docker中根据Images创建容器。
4 Container(容器)
容器是镜像的可运行实例。容器就相当于VMware中每一个克隆出来的虚拟机。但是容器要比虚拟机体积小很多。
5 Registry(仓库)
Docker Registry是一个集中存储与分发镜像的服务。我们构建完Docker镜像后,就可在当前宿主机上运行。但如果想要在其他机器上运行这个镜像,我们就需要手动拷贝。此时,我们可借助Docker Registry来避免镜像的手动拷贝。
一个Docker Registry可包含多个Docker仓库;每个仓库可包含多个镜像标签;每个标签对应一个Docker镜像。这跟Maven的仓库有点类似,如果把Docker Registry比作Maven仓库的话,那么Docker仓库就可理解为某jar包的路径,而镜像标签则可理解为jar包的版本号。
三、 Docker安装与启动
Docker有windows和linux版本。以安装在Linux上进行演示的。 以下安装步骤基于CentOS stream 8,并确保该虚拟机可以连接外网。
1. 安装
如果在网络条件较好的地方推荐使用在线版安装,如果在教室推荐使用离线版
1.1 离线版
把今天文件夹/软件中四个文件都上传到/usr/local/tmp中
1.1.1 安装Container-io
cd /usr/local/tmp
安装container-io,由于container-io需要秘钥,所以需要使用yum安装方式。
所有安装步骤都是有顺序的,顺序乱了,无法安装。
yum localinstall containerd.io-1.2.6-3.3.fc30.x86_64.rpm
提示需要输入y进行确认安装。
1.1.2 安装Docker相关三个rpm
三个安装过程中不要使用yum localinstall,有相互依赖关系,自动下载。
必须按照文档的顺序安装。
安装Docker-Ce的依赖
rpm -ivh libcgroup-0.41-19.el8.x86_64.rpm
安装Docker客户端
rpm -ivh docker-ce-cli-19.03.13-3.el8.x86_64.rpm
安装Docker-ce
rpm -ivh docker-ce-19.03.13-3.el8.x86_64.rpm
1.2 在线版
1.2.1 下载docker-ce repo
为本地yum提供远程repo信息。
curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
1.2.2 安装依赖
yum install -y https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm
1.2.3 安装docker-ce
yum install -y docker-ce
2. 启动
2.1 启动服务
2.1.1 开启Docker服务
systemctl start docker
2.1.2 设置Docker服务开机自启
systemctl enable docker
2.2 查看Docker状态
docker info
结果如下:
三、 镜像加速器配置
默认情况下Docker从Docker Hub上下载镜像资源,但速度很慢,可以通过配置国内的镜像加速器来解决。
本课程以阿里云镜像加速器为例讲解
1.访问阿里云
https://www.aliyun.com/
2. 登录
登录自己的账号
3. 进入容器镜像服务
也可以直接在上面进行搜索“容器镜像服务 ACR”
4. 进入控制管理台
5. 进入镜像加速器
6. 选择对应的OS并配置
把配置镜像加速器里面所有命令执行一遍。
注意:第2行到第6行是一个命令,需要复制这5行一起执行。
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xbyx1r45.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
7. 验证镜像加速器配置
通过docker info命令验证镜像加速器配置,结果如下:
四、Docker镜像操作
1. 什么是Docker镜像
Docker镜像是由文件系统叠加而成(是一种文件的存储形式)。最底端是一个文件引导系统,即bootfs,这很像典型的Linux/Unix的引导文件系统。Docker用户几乎永远不会和引导系统有什么交互。实际上,当一个容器启动后,它将会被移动到内存中,而引导文件系统则会被卸载,以留出更多的内存供磁盘镜像使用。Docker容器启动是需要一些文件的,而这些文件就可以称为Docker镜像。
2. 列出镜像
列出docker下的所有镜像,命令: docker images
结果解释:
变量名 | 变量含义 |
---|---|
REPOSITORY | 镜像所在的仓库名称 |
TAG | 镜像标签(其实就是版本) |
IMAGE ID | 镜像ID |
CREATED | 镜像的创建日期(不是获取该镜像的日期) |
SIZE | 镜像大小 |
3. 搜索镜像
可使用命令搜索需要的镜像,命令: docker search 镜像名称
结果解释:
变量名 | 变量含义 |
---|---|
NAME | 仓库名称 |
DESCRIPTION | 镜像描述 |
STARS | 用户评价,反应一个镜像的受欢迎程度 |
OFFICIAL | 是否官方 |
AUTOMATED | 自动构建,表示该镜像由Docker Hub自动构建流程创建的 |
4. 拉取镜像
拉取镜像相当于从远程Registry中下载镜像到本地,命令:
docker pull 镜像名称:tag
其中:tag可以省略,省略时下载镜像最新版本(lastest)
5. 删除镜像
删除本地镜像使用命令:
docker rmi $IMAGE_ID
docker rmi $REPOSITORY:TAG
五、 Docker容器操作
可以把容器看成简易版的Linux环境(包括root用户权限,进程空间,用户空间和网络空间等)和运行在其中的应用程序。
1 新建容器
docker create [options] 镜像名字或者ID [COMMAND] [ARG...]
写法一:下面命令中
--name是容器名字。名称随意
MYSQL_ROOT_PASSWORD:root用户的密码
最后的mysql是镜像,没有tag时表示:lastest最新版本。
docker create -p 3306:3306 --name suiyi -e MYSQL_ROOT_PASSWORD=smallming mysql:5.7
写法二:每行最后的反斜线 ‘\’,代表命令未完结。
docker create -p 3306:3306 --name mysql_new -e MYSQL_ROOT_PASSWORD=root \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-d mysql
1.1 options 参数说明
变量名 | 变量含义 |
---|---|
–name | 给容器起一个新名字。为容器指定一个名称 |
-i | 以交互模式运行容器,通常与-t连用 |
-t | 为容器重新分配一个伪终端,通常与-i连用 |
-P | 随机端口映射 |
-p | 指定端口映射,hostPost:containerPort |
-e | 配置信息 |
-d | 后台执行 |
-v | 主机和容器的目录映射关系,":"前为主机目录,之后为容器目录 |
2. 新建并启动容器
语法:
docker run [options] 镜像名字或者ID [COMMAND] [ARG...]
写法一:
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
写法二:
docker run -p 3306:3306 --name mysql_new -e MYSQL_ROOT_PASSWORD=root \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-d mysql
2.1 可用参数说明
docker run --help
-d, --detach=false 指定容器运行于前台还是后台,默认为false
-i, --interactive=false 打开STDIN,用于控制台交互
-t, --tty=false 分配tty设备,该可以支持终端登录,默认为false
-u, --user="" 指定容器的用户
-a, --attach=[] 登录容器(必须是以docker run -d启动的容器)
-w, --workdir="" 指定容器的工作目录
-c, --cpu-shares=0 设置容器CPU权重,在CPU共享场景使用
-e, --env=[] 配置信息
-m, --memory="" 指定容器的内存上限
-P, --publish-all=false 指定容器暴露的端口
-p, --publish=[] 指定容器暴露的端口
-h, --hostname="" 指定容器的主机名
-v, --volume=[] 给容器挂载存储卷,挂载到容器的某个目录
--volumes-from=[] 给容器挂载其他容器上的卷,挂载到容器的某个目录
--cap-add=[] 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cap-drop=[] 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cidfile="" 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
--cpuset="" 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
--device=[] 添加主机设备给容器,相当于设备直通
--dns=[] 指定容器的dns服务器
--dns-search=[] 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
--entrypoint="" 覆盖image的入口点
--env-file=[] 指定环境变量文件,文件格式为每行一个环境变量
--expose=[] 指定容器暴露的端口,即修改镜像的暴露端口
--link=[] 指定容器间的关联,使用其他容器的IP、env等信息
--lxc-conf=[] 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
--name="" 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
--net="bridge" 容器网络设置:
bridge 使用docker daemon指定的网桥
host //容器使用主机的网络
container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
none 容器使用自己的网络(类似--net=bridge),但是不进行配置
--privileged=false 指定容器是否为特权容器,特权容器拥有所有root权限
--restart="no" 指定容器停止后的重启策略:
no:容器退出时不重启
on-failure:容器故障退出(返回值非零)时重启
always:容器退出时总是重启
--rm=false 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
--sig-proxy=true 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
3. 列出启动容器
列出正在运行的容器:
docker container ls
查看docker容器进程信息: docker ps [options]
docker ps
3.1 options 参数说明
参数名 | 参数含义 |
---|---|
-l | 显示最近创建的容器 |
-n 数字 | 显示最近n个创建的容器 -n3 |
-a | 列出所有的运行过的容器 |
-q | 列出容器id |
4. 与运行中的容器交互
语法:
docker exec [options] 容器ID [command]
示例:
docker exec -it mysql /bin/bash
4.1 options参数说明
参数名 | 参数含义 |
---|---|
-i | 以交互模式运行容器,通常与-t连用 |
-t | 为容器重新分配一个伪终端,通常与-i连用 |
5. 停止容器
语法:
docker stop 容器ID
示例:
docker stop mysql
6. 启动容器
语法:
docker start 容器ID
示例:
docker start mysql
7. 强制停止容器
不推荐使用,容易造成容器服务不正常关闭,影响后续使用。
语法:
docker kill 容器ID
示例:
docker kill mysql
8. 删除容器
要删除的容器,必须是关闭状态的。
语法:
docker rm 容器ID
示例:
docker rm mysql
9. 查看容器日志
语法:
docker logs -f -t --tail 行数 容器ID
示例:
docker logs -f -t --tail 5 mysql
10. 查看容器中运行的进程
可以知道容器中到底运行的是哪个应用程序。
语法:
docker top 容器ID
示例:
docker top mysql
11. 查看容器内部详情
语法:
docker inspect 容器ID
示例:
docker inspect mysql
12. 复制容器数据到宿主机(复制宿主机数据到容器)
cp 后面,谁在后面表示拷贝到谁里。
语法:
docker cp 容器ID:容器内路径 宿主机路径
docker cp 宿主机路径 容器ID:容器内路径
示例:
复制MySQL配置到宿主机
docker cp mysql:/etc/mysql /tmp/conf
复制宿主机文件到MySQL容器
docker cp /tmp/conf/a.txt mysql:/etc/mysql/
六、 Docker File管理(如何自定义镜像)
Docker File是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。 通过构建一个Java项目镜像来演示Docker File
1. 使用本地命令构建镜像
1.1 下载JDK镜像
一般使用openjdk镜像。
docker search openjdk
docker pull openjdk:11
1.2 创建构建文件
在IDEA新建一个spring boot项目,里面只有一个叫做”/”的控制器,访问后打印demo。把项目打包叫做demojar.jar。并上传到/usr/local/docker中,需要新建docker文件夹, 打包好的jar文件放到docker目录下 ,并且在docker文件夹下面 创建 buildFile文件, 要构建到镜像中的jar文件需要和buildFile处于同一个目录。
touch buildFile
编辑buildFile文件
vim buildFile
按照下面的格式编辑文件
FROM openjdk:11
VOLUME /var/mydatas //数据同步到mydatas目录下
ADD demojar.jar app.jar //将 demojar.jar 重名名 app.jar
ENTRYPOINT ["java","-jar","/app.jar"] //执行 java-jar app.jar 命令
EXPOSE 8080 //映射的端口8080
1.2.1 指定基础镜像,这个需要根据自己配置的仓库上的版本写
FROM openjdk:latest
1.2.2 持久化目录
VOLUME /var/mydatas
1.2.3 指定源包,前者是你的jar包
ADD demojar.jar app.jar
1.2.4 指定容器启动时执行的命令
ENTRYPOINT ["java","-jar","/app.jar"]
1.2.5 对外端口
EXPOSE 8080
1.3 构建镜像
docker build -f 构建文件 -t 镜像名称:TAG .
其中镜像名称和TAG都是自己定义的。
注意最后面有个点。
docker build -f /usr/local/docker/buildFile -t demo:1.0 .
1.4 启动
docker run --name demo -p 8080:8080 -d demo:1.0
2. 使用Maven插件构建镜像
2.1 修改Docker服务配置
vim /usr/lib/systemd/system/docker.service
在ExecStart变量末尾,增加下述配置:注意:一定是同一行,且与原值之间必须有至少一个英文半角空格
-H unix:///var/run/docker.sock -H 0.0.0.0:2375
结果如下:
2.2 重启docker服务
systemctl daemon-reload
systemctl restart docker
2.3 IDEA项目POM依赖
新增plugin插件配置:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.2</version>
<configuration>
<imageName>demo:2.0</imageName> <!--指定镜像名称 仓库/镜像名:标签-->
<baseImage>openjdk:8</baseImage> <!--指定基础镜像-->
<dockerHost>http://192.168.88.129:2375</dockerHost> <!-- 指定服务器仓库地址 -->
<entryPoint>["java","-jar","/${project.build.finalName}.jar"]</entryPoint> <!-- 容器启动执行的命令 -->
<resources>
<resource>
<targetPath>/</targetPath> <!-- 指定要复制的目录路径,这里是当前目录 -->
<directory>${project.build.directory}</directory> <!-- 指定要复制的根目录,这里是target目录 -->
<include>${project.build.finalName}.jar</include> <!-- 指定需要拷贝的文件,这里指最后生成的jar包 -->
</resource>
</resources>
</configuration>
</plugin>
2.4 新增IDEA启动配置
2.4.1 第一步
2.4.1 第二步
2.4.3 第三步
2.4.4 第四步
2.4.5 第五步
2.5 直接可视化操作
注意:必须保证项目有target及下面的jar包。否则需要点击Maven面板clean->install
直接点击docker -> docker:build
七、 阿里云镜像仓库
可以把自己的Docker File上传到阿里云镜像仓库中。上传后可以通过仓库地址随时下载仓库内容。
登录阿里云后进入容器镜像服务-> 控制台,按照下面步骤完成。
1. 新建命名空间
命名空间就是公司名、组织名或个人名。
一个命名空间下可以有多个仓库。
2. 新建仓库
点击创建镜像仓库按钮按照提示填写信息
仓库名称就相当于是镜像名称。例如以前下载MySQL时镜像叫做mysql。mysql就是仓库名。
选择本地仓库。镜像存储在本地仓库中。
3. 创建docker密码
docker login时需要输入密码,需要设置固定密码或临时密码。
演示时以固定密码举例。
4. 点击创建好的镜像仓库
点击创建的镜像仓库名称
按照提示命令进行完成。其中镜像版本就是软件版本。例如:mysql:5.7中5.7就是镜像版本。
注意:创建完成的仓库里面默认没有镜像。一定要先执行 步骤3.将镜像推送给Registry.上传成功后,删除本地镜像。在执行步骤2拉取镜像。
八、 本地镜像仓库
通过构建Docker本地库,可以让项目组内多个Docker的Image公用。
1. 搭建本地仓库
1.1 下载本地仓库镜像
docker pull registry
1.2 修改Docker Service配置
vim /usr/lib/systemd/system/docker.service
修改内容如下:
找到Service节点,在ExecStart属性末尾增加新参数.
其中IP设置为本地仓库IP。5000端口随意的。
--insecure-registry 192.168.88.129:5000
1.3 修改Docker Daemon配置
vim /etc/docker/daemon.json
新增配置内容:注意IP和端口跟上面的配置相同的。
{
"insecure-registries":["192.168.88.129:5000"]
}
具体如下:
1.4 重启Docker服务
systemctl daemon-reload
systemctl restart docker
1.5 启动容器
docker run -p 5000:5000 -v /opt/registry:/var/lib/registry --name registry -d registry
1.6 容器启动状态
docker ps -l
1.7 浏览器查看本地仓库
http://ip:5000/v2
2. push镜像
命令中使用IP进行push的,要知道本地registry和docker不是必须在一台服务器的。
docker tag [ImageId] ip:5000/[镜像名称]:[镜像版本号]
docker push ip:5000/[镜像名称]:[镜像版本号]
具体命令如下:两个命令必须按照顺序都执行。
docker tag df689c674c72 192.168.88.129:5000/demo:1.0
docker push 192.168.88.129:5000/demo:1.0
3. pull镜像
语法:
docker pull ip:5000/[镜像名称]:[镜像版本号]
具体命令如下:
docker pull 192.168.88.129:5000/demo:1.0
九、 Docker的数据管理
1. 数据卷管理
数据卷的作用是将宿主机的某个磁盘目录映射到容器的某个目录,从而实现宿主机和容器之间的数据共享。
docker run|create --name [容器名称] -v [宿主机目录]:[容器目录] [镜像名称]
示例:
在虚拟机中创建一个目录。虚拟机中共享目录
mkdir /usr/local/vvv
创建容器并设置共享目录,该目录会自动帮助创建. -v 参数第一路径虚拟机中的路径。第二个路径容器的路径
docker run --name vvv -p 3399:3306 -v /usr/local/vvv:/mydatas -d -e MYSQL_ROOT_PASSWORD=root mysql
进入容器内部
docker exec -it vvv /bin/bash
进入mydatas
cd /mydatas
新建一个文件
touch jqk
退出容器
exit
在虚拟机中/usr/local/vvv发现多了jqk文件说明,共享目录设置成功。
2. 数据卷容器管理
数据卷容器的作用是实现多个容器之间的数据共享。其实,数据卷容器也是一个容器,但是与其他Docker容器不一样的是,数据卷容器是专门用来提供数据卷给其他容器进行挂载操作。
2.1 创建数据卷容器
创建容器,并在容器中创建目录/datas。其中/datas是共享目录。
docker run --name my_datas -v /datas -e MYSQL_ROOT_PASSWORD=root -d mysql
2.2 创建容器并使用数据卷容器
命令格式:
通过–volumes-from参数设定从哪个数据卷容器创建新的容器,必须通过数据卷容器进行创建,否则无法共享。
docker run --volumes-from [数据卷容器名或ID] [options] [镜像名或ID]
具体如下:
创建两个容器,都指定my_datas为共享容器
第一个容器:
docker run --name c1 --volumes-from my_datas -e MYSQL_ROOT_PASSWORD=root -d mysql
第二个容器
docker run --name c2 --volumes-from my_datas -e MYSQL_ROOT_PASSWORD=root -d mysql
2.3 测试
2.3.1 访问c1容器并在共享目录中写入数据
docker exec -it c1 bash
> ls /
> touch /datas/readme
> exit
2.3.2 访问c2容器并读取共享目录中的数据
docker exec -it c2 bash
> ls /datas
如果有readme的文件,说明共享成功。
十、 Docker容器生命周期
Docker的生命周期其实就是Docker容器从创建到被销毁的过程。
在课堂上使用过docker start和docker stop,图中的命令也是docker支持的命令。
1. 状态介绍
1.1 圆形
圆形代表的是稳定状态。代表容器的五种状态:
- created:初建状态
- running:运行状态
- stopped:停止状态
- paused: 暂停状态
- deleted:删除状态
1.2 长方形
代表容器在执行某种命令后进入的状态:状态是临时状态。
- docker create : 创建容器后,不立即启动运行,容器进入初建状态;
- docker run : 创建容器,并立即启动运行,进入运行状态;
- docker start : 容器转为运行状态;
- docker stop : 容器将转入停止状态;
- docker kill : 容器在故障(死机)时,执行kill(断电),容器转入停止状态,这种操作容易丢失数据,除非必要,否则不建议使用;
- docker restart : 重启容器,容器转入运行状态;
- docker pause : 容器进入暂停状态;
- docker unpause : 取消暂停状态,容器进入运行状态;
- docker rm : 删除容器,容器转入删除状态(如果没有保存相应的数据库,则状态不可见)。
1.3 菱形
需要根据实际情况选择的操作
1.3.1 killed by out-of-memory(因内存不足被终止)
宿主机内存被耗尽,也被称为OOM:非计划终止
这时需要杀死最吃内存的容器
然后进行选择操作
container process exitde(异常终止)
出现容器被终止后,将进入Should restart?选择操作:
- yes 需要重启,容器执行start命令,转为运行状态。
- no 不需要重启,容器转为停止状态。
##### 2.3.2 访问c2容器并读取共享目录中的数据
~~~shell
docker exec -it c2 bash
> ls /datas
如果有readme的文件,说明共享成功。
十、 Docker容器生命周期
Docker的生命周期其实就是Docker容器从创建到被销毁的过程。
在课堂上使用过docker start和docker stop,图中的命令也是docker支持的命令。
[外链图片转存中…(img-eXR9QyFY-1657355001925)]
1. 状态介绍
1.1 圆形
圆形代表的是稳定状态。代表容器的五种状态:
- created:初建状态
- running:运行状态
- stopped:停止状态
- paused: 暂停状态
- deleted:删除状态
1.2 长方形
代表容器在执行某种命令后进入的状态:状态是临时状态。
- docker create : 创建容器后,不立即启动运行,容器进入初建状态;
- docker run : 创建容器,并立即启动运行,进入运行状态;
- docker start : 容器转为运行状态;
- docker stop : 容器将转入停止状态;
- docker kill : 容器在故障(死机)时,执行kill(断电),容器转入停止状态,这种操作容易丢失数据,除非必要,否则不建议使用;
- docker restart : 重启容器,容器转入运行状态;
- docker pause : 容器进入暂停状态;
- docker unpause : 取消暂停状态,容器进入运行状态;
- docker rm : 删除容器,容器转入删除状态(如果没有保存相应的数据库,则状态不可见)。
1.3 菱形
需要根据实际情况选择的操作
1.3.1 killed by out-of-memory(因内存不足被终止)
宿主机内存被耗尽,也被称为OOM:非计划终止
这时需要杀死最吃内存的容器
然后进行选择操作
container process exitde(异常终止)
出现容器被终止后,将进入Should restart?选择操作:
- yes 需要重启,容器执行start命令,转为运行状态。
- no 不需要重启,容器转为停止状态。