通俗地讲,容器是镜像的运行实体。镜像是静态的只读文件,而容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。即容器运行着真正的应用进程。容器有初建、运行、停止、暂停和删除五种状态
虽然容器的本质是主机上运行的一个进程,但是容器有自己独立的命名空间隔离和资源限制。也就是说,在容器内部,无法看到主机上的进程、环境变量、网络等信息,这是容器与直接运行在主机上进程的本质区别
容器是基于镜像创建的可运行实例,并且单独存在,一个镜像可以创建出多个容器。运行容器化环境时,实际上是在容器内部创建该文件系统的读写副本。 这将添加一个容器层,该层允许修改镜像的整个副本
镜像与容器就相当于同样是开发商提供的毛坯房,但是两家人装修出来的完全不一样
或者我们都学习了 Java 或者 C++之类的面向对象的语言,可以理解为镜像为基础类,容器是实例化出来的一个个对象,没有用户需要的不一样,里面的内容也就不一样了
为什么需要容器?
镜像是静态的文件,并不能提供服务,就像我拿了个 Linux 或者 Windows 的光盘一样,只有安装到主机里面运行起来才能对外提供服务,我们才能使用
容器带来哪些收益呢,参考我之前的文章:为什么要虚拟化、容器化?
容器的生命周期是容器可能处于的状态:
各生命周期之间的转换关系如图所示
docker create:创建容器后,不立即启动运行,容器进入初建状态
docker run:创建容器,并立即启动运行,进入运行状态
docker start:容器转为运行状态
docker stop:容器将转入停止状态
docker kill:容器在故障(死机)时,执行 kill(断电),容器转入停止状态,这种操作容易丢失数据,除非必要,否则不建议使用
docker restart:重启容器,容器转入运行状态
docker pause:容器进入暂停状态
docker unpause: 取消暂停状态,容器进入运行状态
docker rm:删除容器,容器转入删除状态
killed by out-of-memory(因内存不足被终止):宿主机内存被耗尽,也被称为 OOM,非计划终止 这时需要杀死最吃内存的容器
container process exitde(异常终止):出现容器被终止后,将进入 Should restart?
Docker 在处理 OOM 事件时分为三种情况
(1)如果容器中的应用耗尽了主机系统分配给容器的内存限额,就会触发 OOM 事件。例如,在容器当中,部署了一个 web 服务。假设主机分配给此容器的内存上限为 1G,当脚本申请的内存大于 1G 时,此容器就会触发 OOM 事件。而在这种情况下,此容器将会被强制关闭。但需要注意的是,此时关闭容器的并非是 Docker Daemon,而是宿主机操作系统。因为一个容器其实就是一组运行在宿主机操作系统当中的进程,宿主机操作系统通过cgroups 对这组进程设定资源上限,当这些进程申请的资源到达上限时,触发的是宿主机操作系统的内核 OOM 事件,因此最终是由宿主机内核来关闭这些进程
(2) 如果用户不想关闭这个容器,那么可以选择- -oom-kill-disable 来禁用 OOM-Killer。使用此参数时,仍需要注意,如果使用-m 设置了此容器内存上限,那么当容器到达内存资源上限时,主机不会关闭容器,但也不会继续向此容器继续分配资源,此时容器将处于 hung 状态。只需要将最坏的情况封闭在一定范围之内,而不至于蔓延出去
(3)如果用户使用了- -oom-kill-disable,但也没有使用-m 来设定上限,因而此时此容器将会尽可能多地使用主机内存资源。换言之,主机内存有多大,它就将用多大
每个容器内部都存在一个 Init 进程,容器中其他所有进程都是此进程的子进程。运行的容器是因为 Init 进程在运行,如果一个子进程因为某种原因造成了退出,那么其父进程也会同步退出,直至 Init 进程也退出。当 Init 进程退出时,也就代表着此容器被关闭。docker 目前没有办法知道此时的进程退出属于正常退出还是异常退出。当出现容器关闭情况时,Docker Daemon 会尝试再次重新将此容器由 Stopped 状态转为 Running 状态。只有设置了- -restart 参数的容器,Docker Daemon 才会去尝试启动,否则容器会保持停止状态
Docker“剥夺”了此容器的 CPU 资源。而其他资源,如 Memory 资源、Network 资源等还保留未动。如此一来,失去了 CPU 资源的进程,是不会被主机内核系统所调度的,所以此容器就处于“冰封”状态
命令 | 别名 | 功能 |
---|---|---|
docker create | docker container create | 创建容器 |
docker run | docker container run | 运行容器 |
docker attach | docker container attach | 连接到正在运行中的容器 |
docker commit | docker container commit | 将镜像提交为容器 |
docker cp | docker container cp | 在容器和宿主机之间拷贝 |
docker diff | docker container diff | 检查容器里文件结构的更改 |
docker exec | docker container exec | 在运行的容器中执行命令 |
docker export | docker container export | 将容器导出为 tar |
docker container inspect | 查看容器详细信息 | |
docker kill | docker container kill | 杀死容器 |
docker logs | docker container logs | 查看日志 |
docker ps | docker container ls, docker container list, docker container ps | 查看正在运行的进程 |
docker pause | docker container pause | 暂停进程 |
docker port | docker container port | 查看容器的端口映射 |
docker container prune | 删除停止的容器 | |
docker rename | docker container rename | 重命名容器 |
docker restart | docker container restart | 重启容器 |
docker rm | docker container rm,docker container remove | 删除容器 |
docker start | docker container start | 启动容器 |
docker stats | docker container stats | 查看资源占用信息 |
docker stop | docker container stop | 停止容器 |
docker top | docker container top | 查看某个容器的资源占用 |
docker unpause | docker container unpause | 继续运行容器 |
docker update | docker container update | 更新容器配置 |
docker wait | docker container wait | 阻止一个或多个容器停止,然后打印退出代码 |
docker create
创建一个新的容器但不启动它
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
别名
docker container create
关键参数
-i: 以交互模式运行容器,通常与 -t 同时使用
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
- -name=“nginx-lb”: 为容器指定一个名称
-h “mars”: 指定容器的 hostname
-e username=“ritchie”: 设置环境变量
- -cpuset-cpus=“0-2” or - -cpuset-cpus=“0,1,2”: 绑定容器到指定 CPU 运行
-m :设置容器使用内存最大值
- -network=“bridge”: 指定容器的网络连接类型
- -link=[]: 添加链接到另一个容器
- -volume , -v: 绑定一个卷
- -rm :shell 退出的时候自动删除容器
- -restart:自动重启
这个命令和 docker run 的参数基本一样
创建一个容器,它的状态就是created
docker start
启动停止的容器或者已经创建的容器
docker start [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container start
启动刚刚创建的容器
docker logs
查看容器日志
docker logs [OPTIONS] CONTAINER
别名
docker container logs
关键参数
-f ,- -follow: 跟踪日志输出
- -since :显示某个开始时间的所有日志
-t,- -timestamps : 显示时间戳
-n,- -tail :仅列出最新 N 条容器日志
不带参数查看log
查看容器 mywebsite1 从 2016 年 7 月 1 日后的最新 2 条日志
docker logs --since="2016-07-01" --tail=2 mywebsite1
docker attach
连接到正在运行中的容器
docker attach [OPTIONS] CONTAINER
别名
docker container attach
关键参数
- -sig-proxy:是否将所有信号代理,默认是 true,如果设置为 false,退出的话不会影响容器,否则退出会导致容器退出
链接前面启动的mywebsite1容器,并访问页面,此时就会产生前台日志
此时按下ctrl+c,此时就会收到2号信号,容器就会停止
如何不退出呢?此时就需要使用到 - -sig-proxy 参数,将退出信号拦截掉
docker attach --sig-proxy=false mywebsite1
docker exec
在容器中执行命令
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
别名
docker container exec
关键参数
-d :分离模式: 在后台运行
-i :即使没有附加也保持 STDIN 打开
-t :分配一个伪终端
-e :设置环境变量
-u,- -user :指定用户 “
-w,- -workdir:指定工作目录
参数-it
在容器 mywebsite1 中以交互模式执行 echo
docker exec -it mywebsite1 echo "Hello bit"
在容器 mywebsite1中以交互模式打开 shell
docker exec -it mywebsite1 bash
通过 id 进入 mywebsite1 中
参数-e
设置环境变量
docker exec -it -e mynginx=fl mywebsite1 bash
参数-u
指定用户为nginx,查看mywebsite1的nginx的版本,前提是用户存在,如如果用户不存在,则会报错
docker exec -it -u nginx mywebsite1 nginx -v
参数-w
指定工作目录为/etc
docker exec -it -w /etc mywebsite1 bash
docker stop
停止正在运行的容器
docker stop [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container stop
关键参数
-s:发送的信号
停止正在运行的 mywebsite1
docker stop mywebsite1
无论容器正在后台运行还是正在交换,docker stop 都能将其停止掉
docker restart
重启容器
docker restart [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container restart
关键参数
-s :发送信号
docker restart=docker stop + docker start
在终端1进行日志跟踪
docker logs -f -n 2 mywebsite1
docker restart mywebsite1
docker kill
强制退出容器
docker kill [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container kill
关键参数
-s :发送的信号
注意事项:Docker stop 发送的是 SIGTERM 信号,docker kill 发送的是 SIGKILL 信号
终端1进行日志跟踪
docker kill mywebsite1
可以对比一下docker stop,还对打印一些信息,而docker kill 什么都不会打印
docker top
查看容器中运行的进程信息,支持 ps 命令参数
docker top CONTAINER [ps OPTIONS]
别名
docker container top
注意事项:容器运行时不一定有/bin/bash 终端来交互执行 top 命令,而且容器还不一定有top 命令,可以使用 docker top 来实现查看 container 中正在运行的进程
查看容器mywebsite1进程的信息
docker top mywebsite1
docker top mywebsite1 aux
docker stats
显示容器资源的使用情况,包括:CPU、内存、网络 I/O 等
docker stats [OPTIONS] [CONTAINER...]
别名
docker container stats
关键参数
- -all , -a :显示所有的容器,包括未运行的
- -format :指定返回值的模板文件。如 table,json
- -no-stream :展示当前状态就直接退出了,不再实时更新
- -no-trunc :不截断输出
返回报文
CONTAINER ID 与 NAME: 容器 ID 与名称
CPU % 与 MEM %: 容器使用的 CPU 和内存的百分比
MEM USAGE / LIMIT: 容器正在使用的总内存,以及允许使用的内存总量
NET I/O: 容器通过其网络接口发送和接收的数据量
BLOCK I/O: 容器从主机上的块设备读取和写入的数据量
PIDs: 容器创建的进程或线程数
列出所有在运行的容器信息
docker stats
列出所有在运行的容器信息,json 格式显示
docker stats --format json
因为是实时刷新的,屏幕会一直闪,我这里就截了一张图,看不出来是实时刷新
使用 --no-stream,展示当前状态的快照
docker stats --no-stream
docker container inspect
查看容器详细信息
docker container inspect [OPTIONS] CONTAINER [CONTAINER...]
关键参数
-f :指定返回值的模板文件。如 table、json
-s :显示总的文件大小
查看容器mywebsite1的信息
docker container inspect
注意事项:docker inspect 会自动检查是镜像还是容器然后显示相信信息
显示对应的大小
docker inspect -s mywebsite1
docker port
用于列出指定的容器的端口映射,或者查找将 PRIVATE_PORT NAT 到面向公众的端口
docker port CONTAINER [PRIVATE_PORT[/PROTO]]
别名
docker container port
查看容器website1的端口映射
docker port mywebsite1
查看容器website1是否有81端口的映射
docker port mywebsite1 81
结果并没有81端口的映射
docker cp
在容器和宿主机之间拷贝文件
容器和宿主机之间发生了Mount隔离(文件隔离),如果想把文件进行相互之间的拷贝,需要通过docker engine这个桥梁
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
别名
docker container cp
将容器mywebsite1里面的html文件拷贝宿主机的/data/fl下
docker cp mywebsite1:/usr/share/nginx/html/index.html ./
将index.html文件修改一下,再拷贝到容器website1中
docker cp ./index.html mywebsite1:/usr/share/nginx/html/index.html
进入容器内部,查看是否拷贝成功
docker diff
检查容器里文件结构的更改
docker diff CONTAINER
检查容器mywebsite1的文件结构
docker diff mywebsite1
在容器内加一个文件
再次查看容器mywebsite1的文件结构
docker commit
从容器创建一个新的镜像
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
参数
-a :提交的镜像作者
-c :使用 Dockerfile 指令来创建镜像;可以修改启动指令
-m :提交时的说明文字
-p :在 commit 时,将容器暂停
将容器mywebsite1创建一个名为mywebsite1:1.0
docker commit mywebsite1 mywebsite1:1.0
创建镜像时,自定义镜像的信息
docker commit -a 'fl' -m 'create by fl' -p mywebsite1 mywebsite1:2.0
查看mywebsite1:2.0的详细信息中是否有我们自定义的信息
docker inspect mywebsite1:2.0 | grep 'fl'
使用参数-c来修改启动指令
docker commit -c 'CMD ["tail","-f","/etc/hosts"]' -p mywebsite1 mywebsite1:3.0
查看mywebsite:3.0的启动信息
docker inspect mywebsite:3.0
启动mywebsite1:3.0,对比mywebsite1的启动信息
docker pause
暂停容器中所有的进程
docker pause CONTAINER [CONTAINER...]
别名
docker container pause
docker unpause
恢复容器中所有的进程
docker unpause CONTAINER [CONTAINER...]
别名
docker container unpause
docker rm
删除停止的容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container rm
关键参数
-f :通过 SIGKILL 信号强制删除一个运行中的容器
删除 mywebsite1 容器
docker stop mywebsite1
docker rm mywebsite1
删除所有停止的容器,配合shell脚本使用
docker rm $(docker ps -aq)
docker export
导出容器内容为 tar 文件(相当于是容器转为镜像)
docker export [OPTIONS] CONTAINER
别名
docker container export
关键参数
-o:写入到文件
将mywebsite1导入到指定目录下
镜像命令:docker import
从归档文件中创建镜像
docker import和docker export是相互配合使用的
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
别名
docker image import
关键参数
-c:应用 docker 指令创建镜像
-m:提交时的说明文字
将刚刚的tar文件转换为镜像
docker import mywebsite1.tar mywebsite1:5.0
docker save 和 docker load 也能完成镜像迁移,它们与docker export 和 docker import 有什么区别呢?
首先查看nginx:1.21.3的信息,因为mywebsite1就是由它来的
再看一下导出的mywebsite1:5.0的信息
可以发现Env、Cmd等信息都已经丢了,因此使用docker export 和 docker import会丢失源数据信息,而docker save 和 docker load会携带源数据信息。
在进行镜像迁移时,往往使用docker save 和 docker load
使用参数-c指定启动信息,-m指定描述镜像信息
docker import -c 'CMD ["nginx","-g","deamon off;"]' -m "create by fl" mywebsite1.tar mywebsite1:6.0
查看mywebsite1:6.0的详细信息
docker wait
阻塞运行直到容器停止,然后打印出它的退出代码
docker wait CONTAINER [CONTAINER...]
别名
docker container wait
等待mywebsite1容器停止,并打印它的退出码
因为mywebsite1还在运行,所以当前的终端hang住了
用另一个终端将mywebsite1杀死
docker rename
重命名容器
docker rename CONTAINER NEW_NAME
别名
docker container rename
将mywebsite1改为mywebsite2
docker rename mywebsite1 mywebsite2
docker container prune
删除所有停止的容器
docker container prune [OPTIONS]
关键参数
-f, - -force:不提示是否进行确认
删除当前停止的容器
docker container prune
docker update
更新容器配置
docker update [OPTIONS] CONTAINER [CONTAINER...]
别名
docker container update
关键参数
- -cpus:cpu 数量
- -cpuset-cpus :使用哪些 cpu
- -memory :内存限制
- -memory-swap:交换内存
- -cpu-period :是用来指定容器对 CPU 的使用要在多长时间内做一次重新分配
- -cpu-quota:是用来指定在这个周期内,最多可以有多少时间用来跑这个容器
查看mywebsite1使用的资源
docker stats mywebsite1
将mywebsite1的内存限制改为300m,交换内存不设限制
docker update -m 300m --memory-swap -1 mywebsite1
命令 | 解释 |
---|---|
docker container ls -qf name=xxx | 根据名称过滤得到容器编号 |
docker container ls --filter status=running | 根据状态过滤容器信息 |
docker container ls -aq | 静默获取全部容器 id |
docker container ls --filter ancestor=xxx | 过滤镜像名为 xxx 的容器信息 |
docker container ls --filter ancestor=xxx | 过滤镜像 id 为 xxx 的容器信息 |
-a:表示打印所有的容器信息, 包括正在运行和已经退出的
-q: 表示只返回容器 ID
-f: 表示基于给的条件过滤 等价于 --filter 选项
docker container ls 可以简写为docker ps
批量删除容器
docker rm $(docker ps -aq)
按照状态过滤删除已经退出的容器
docker rm $(docker ps -q -f status=exited)
attached 模式
# 通过 nginx 镜像创建一个容器, 映射 80 端口
docker run -p 80:80 nginx:1.23.3
通过上述方式创建容器,就是 attached 模式,这样容器会在前台运行
访问服务器网址的时候,每访问一次,命令窗口就会打印一次日志,Docker 容器的日志会实时的展现到窗口并且占用此端口
如果是在 Linux 服务器上,按 Ctrl+C 就会停止掉 Docker 服务,很容易误操作,所以我们需要一个更好的,更稳定的模式,对应的是 detached 模式
attached 模式仅适用于容器和程序的调试阶段
detached 模式
在 docker container run -p 80:80 nginx 命令基础上加一个-d 或者–detach选项表示 detached 模式, 即在后台执行
在后台运行,启动后只显示容器 ID,并且可以输入任何命令
就算关掉窗口依然继续运行,停止和删除容器都需要使用 shell 命令,减少了很多的误操作
比起 attached 模式更建议使用
interactive 模式
当我们创建好一个容器之后, 可能需要去容器内部获取一些信息或执行一些命令,就需要进入到交互式模式。例如创建一个 centos 容器之后,需要到系统里输入各种Shell 命令和系统进行交互就需要进入交互式模式才可以完成
创建运行容器并进入到交互模式
docker run -it nginx:1.21.3 bash
进入到容器的交互 shell 中,可以在该 shell 下执行对应的命令
-i:保持容器运行。通常与 -t 同时使用,加入 it 这两个参数后,容器创建后自动进入容器中,退出容器后,容器自动关闭
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用
创建运行容器并进入到交互模式,然后输入exit退出后,容器也会停止
针对一个已经运行的容器里进入到交互模式
在后台创建运行 nginx 容器
docker container run -d -p 82:80 nginx:1.21.3
进入该容器的交互模式
docker container exec -it 123e8b72463f bash
针对一个已经运行的容器里进入到交互模式,然后输入exit退出后,容器不会退出
容器重启选项如下:
如果容器启动时没有设置 --restart 参数,则通过下面命令进行更新:
docker update --restart=always [容器名]
交互式启动nginx容器,在容器退出时总是重启
docker run -it --name mynginx721 -p 80:80 --restart=always nginx:1.21.3 bash
如果使用了docker stop, --restart=always是不会生效的,也就是不会重启
启动一个 nginx 容器,配置环境变量,TEST=1
启动一个nginx容器,使用 --env-file 参数手动指定环境变量的配置文件
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=fl@mysql -p 6379:3306 mysql:5.7
如果本地没有mysql:5.7,那么会自动从docker hub上拉取下来
进入mysql内部,并登录
docker exec -it mysql bash
做一些基本检测,创建数据库,创建表,插入数据
通过一个可视化工具进行连接,注意我这里宿主机端口是6379
拉取镜像并启动容器
docker run --name redis -d -p 6379:6379 redis:7
进入容器,进行简单的测试
docker exec -it redis bash
拉取centos:7
docker pull centos:7
启动容器并进入
docker run -it --name mycpp centos:7 bash
因为默认Yum源为centos的官方地址,所以在国内使用很慢甚至无法访问,因此需要在容器内部配置yum源信息
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=http://mirrors.tuna.tsinghua.edu.cn/centos|g' \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo
更新缓存
yum makecache
查看gcc是否安装,如果没有就安装
安装成功后,写一个简单的c语言代码,并用gcc编译,运行
docker create、docker start 和 docker run 有什么区别?
docker create 命令从 Docker 映像创建一个全新的容器。但是,它不会立即运行它。
docker start 命令将启动任何已停止的容器。如果使用 docker create 命令创建容器,则可以使用此命令启动它。
docker run 命令是创建和启动的组合,因为它创建了一个新容器并立即启动它。实际上,如果 docker run 命令在您的系统上找不到上述映像,它可以从 Docker Hub 中提取映像。
docker import 和 docker load 有什么区别?
想要了解 docker load 与 docker import 命令的区别,还必须知道 docker save与 docker export 命令:
会保存镜像的所有历史记录
容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照
既可以使用 docker load 命令来导入镜像库存储文件到本地镜像库,也可以使用docker import 命令来导入一个容器快照到本地镜像库。
两者的区别在于容器快照将会丢弃所有的历史记录和元数据信息,而镜像存储文件将保存完整记录,体积也会更大。
docker rm & docker rmi & docker prune 的差异?
docker rm:删除一个或多个容器
docker rmi:删除一个或多个镜像
docker prune:用来删除不再使用的 docker 对象