容器是镜像的运行实体,镜像是只读的静态文件,而容器在运行的时候需要有可写的文件层,所以在运行容器化环境的时候,实际上是在容器内创建该文件系统的读写副本,这将添加一个容器层,这一层允许修改镜像的整个副本。
容器的本质是主机上运行的一个进程,但容器有自己独立的命名空间隔离和资源的限制,也就是说,在容器内部是无法看到主机上的进程,环境变量和网络等信息。
容器有初建,运行,停止,暂停,删除五种状态。
容器生命周期
OOM(Out Of Memory)
docker在处理OOM事件时分为3种情况:
-
如果容器中应用耗尽了主机系统分配给容器的内存限额,就会触发OOM事件。例如在容器中部署了一个Web服务,主机分配给此容器的内存上限是1G,当这个服务申请的内存大于1G时,此容器就会触发OOM事件。在这种情况下,此容器会被强制关闭。
此时关闭容器的并不是docker daemon(docker守护进程),而是宿主机操作系统。因为一个容器其实就是一组运行在宿主机操作系统当中的进程,宿主机通过cgroup对这组进程设置资源上限,当这些进程申请的资源到达上限的时候,触发的是宿主机操作系统的内核OOM事件,最终是由宿主机的内核来关闭这些进程的。
-
如果用户不想关闭这个容器,可以选择--oom-kill-disable来禁用OOM-Killer,但仍需要注意,如果使用-m设置了此容器的内存上限,当容器达到内存资源上限的时候,主机不会关闭容器,但也不会再为此容器分配资源,此时容器处于hung状态。
-
如果用户使用了--oom-kill-disable,但也没有使用-m设置内存上限,此时容器就会尽可能多使用主机内存资源,主机内存有多大,容器内存就有多大。
容器异常退出
每个容器里都有一个init进程,容器中的其他所有进程都是此进程的子进程。
如果一个子进程因为某种原因造成了退出,那么其父进程也会同步退出,这种退出一层层往上传,直到init进程也退出。
当init进程退出了的时候,代表此容器被关闭,但docker目前没有办法知道此时的进程退出是属于正常退出还是异常退出。
当出现容器关闭情况的时候,docker守护进程会尝试再次将此容器由stopped状态转为running状态(只有设置了--restart参数的容器,docker守护进程才会去尝试启动,否则容器会保持停止的状态)。
容器暂停
docker剥夺了此容器的cpu资源,但内存资源,网络资源等其他资源还保留着没有动,这样,失去了CPU资源的进程,是不会被主机内核系统调度的,容器就处于暂停状态。
命令
docker create
创建一个新的容器。
bash
docker create [options] Image [command] [arg...]
-i表示以交互模式运行容器,也就是说输入命令可以得到对应的返回结果,但没有终端显示,所以一般会和-t同时使用
-P表示随机端口映射,容器内部端口随机映射到主机的端口。
-p表示指定端口映射,格式为主机端口:容器端口
-t为容器分配一个伪输入终端,通常与-i同时使用
--name="名称"表示为容器指定一个名称
-h "mars"表示指定容器的hostname
-e username="xxx"设置环境变量
--cpuset-cpus="0-2"or--cpuset-cpus="0,1,2"绑定容器到指定的cpu上运行
-m设置容器使用内存的最大值
--network="bridge"指定容器的网络连接类型
--link=[]添加连接到另一个容器
--volume绑定一个卷
--rm表示在退出的时候自动删除容器
--restart自动重启
docker run
创建一个容器并运行一个命令。
bash
docker run [options] image [command] [arg...]
-d表示后台运行容器,并且返回容器ID
-i表示以交互模式运行容器,也就是说输入命令可以得到对应的返回结果,但没有终端显示,所以一般会和-t同时使用
-P表示随机端口映射,容器内部端口随机映射到主机的端口。
-p表示指定端口映射,格式为主机端口:容器端口
-t为容器分配一个伪输入终端,通常与-i同时使用
--name="名称"表示为容器指定一个名称
-h "mars"表示指定容器的hostname
-e username="xxx"设置环境变量
--cpuset-cpus="0-2"or--cpuset-cpus="0,1,2"绑定容器到指定的cpu上运行
-m设置容器使用内存的最大值
--network="bridge"指定容器的网络连接类型
--link=[]添加连接到另一个容器
--volume绑定一个卷
--rm表示在退出的时候自动删除容器
--restart自动重启
--restart=no默认值不自动重启
--restart=on-failure:n表示若容器退出状态为非0,则docker会自动重启容器,还可以指定重启次数,比如说n指定为3,那么最多重启次数为3
--restart=always表示容器退出的时候总是重启
--restart=unless-stopped表示容器退出的时候总是重启,但不考虑docker守护进程启动时就已经停止的容器
如果容器启动的时候没有设置--restart参数,可以通过docker update --restart=always [容器名]进行更新


docker ps
列出容器。
bash
docker ps [options]
-a表示显示所有容器,包括未运行的
-f根据条件过滤显示的内容
--format指定返回值的模板文件,例如json
-l显示latest的容器
-n列出最近创建的n个容器
--no-trunc表示不截断输出
-q静默模式,只显示容器编号
-s显示总的文件大小

docker logs
用于查看功能日志。
bash
docker logs [options] container
-f表示跟踪日志输出
--since显示某个开始时间的所有日志
-t显示时间戳
-n仅列出最新的n条容器日志

docker attach
用于连接到正在运行中的容器。
bash
docker attach [option] container
--sig-proxy表示将信号代理,默认为true,如果设置为false,退出的话不会影响容器,否则退出就会导致容器退出。
docker exec
用于在正在运行的容器内部执行命令。
bash
docker exec [options] container command [arg...]
-d在后台运行
-i即使没有附加也保持stdin(标准输入)打开
-t分配一个伪终端
-e设置环境变量
-u指定用户
-w指定工作目录

docker start
用于启动停止的容器。
bash
docker start [options] container [container2....]

docker stop
停止正在运行的容器。
bash
docker stop [options] container1 [container2....]
-s指定发送的信号,不使用默认的信号SIGTERM

docker restart
重启容器。
bash
docker restart [options] container1 [container2....]
-s指定发送的信号,不使用默认的信号

docker kill
强制退出容器。
bash
docker kill [options] container1 [container2...]
-s指定发送的信号,不使用默认的信号SIGKILL

docker top
容器运行的时候不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top命令,所以想要查看容器中运行的进程信息可以使用次命令,支持ps命令参数。
bash
docker top container [ps options]
docker stats
显示容器资源使用情况,包括cpu,内存,网络IO等。
bash
docker stats [option] [container]
--all显示所有的容器,包括未运行的
--format指定返回值的模板文件,例如json文件
--no-stream展示当前状态就直接退出了,不再实时更新
--no-trunc不截断输出
docker container inspect
用于查看容器详细信息。
bash
docker container inspect [options] container1 [container2...]
-f指定返回值的模板文件,例如json
-s显示总的文件大小

docker port
用于查找将PRIVATE_PORT(容器里的私有端口) NAT(端口映射)到面向公众的端口。
bash
docker port container [PRIVATE_PORT[/协议]]
docker cp
在容器和宿主机之间拷贝文件。
bash
#将主机的文件拷贝到容器里
docker cp [options] host_path|stdin container:con_path
#将容器里的文件拷贝到主机上
docker cp [options] container:con_path host_path|stdin
docker diff
用于检查容器里文件结构的更改。
bash
docker diff container
docker commit
从容器里创建一个新的镜像。
bash
docker commit [options] container [repository[:tag]]
-a提交的镜像作者
-c使用dockerfile指令来创建镜像,可以修改启动指令
-m提交时候的说明文字
-p在commit的时候将容器暂停
docker pause
暂停容器中所有的进程。
bash
docker pause container1 [container2...]

docker unpause
恢复容器中所有的进程。
bash
docker unpause container1 [container2...]

docker rm
用于删除停止的容器。
bash
docker rm [options] container1 [container2...]
-f通过SIGKILL信号强制删除一个运行中的容器

docker export
用于导出容器内容为tar文件。
bash
docker export [options] container
-o表示写入到文件
docker wait
阻塞运行,等待容器停止,然后打印容器的退出代码。
bash
docker wait container1 [container2...]
docker rename
用于重命名容器。
bash
docker rename container new_name
docker container prune
删除所有停止的容器。
bash
docker container prune [options]
-f表示不提示是否进行确认
docker update
更新容器配置。
bash
docker update [options] container1 [container2...]
--cpus表示cpu的数量
--cpuset-cpus表示使用哪些cpu
--memory表示内存限制
--memory-swap表示交换内存
--cpu-period用来指定容器对cpu的使用要在多长时间内做一次重新分配
--cpu-quota是用来指定在这个周期内,最多可以有多少时间来跑这个容器
操作
交互模式
attached模式
- 通过nginx镜像创建一个容器,映射80端口。
bash
docker container run -p 80:80 nginx
以上述方式创建容器,就是attached模式,这样容器就会在前台运行,当访问服务器网址的时候,每访问一次,命令窗口就会打印一次日志,此模式可以用ctrl+c中止服务。

detached模式
在创建attached容器命令基础上加一个-d或者--detach选项就是detached模式,表示在后台执行。
bash
docker container run -p 80:80 nginx -d
在后台运行,启动的时候只显示容器ID,并且控制台和平常一样,可以输入ls等指令,并得到返回值。
即使关掉窗口依旧可以运行,停止和删除容器都需要使用shell命令。
下面使用docker container logs命令查看后台日志。

如果我们想要将detached模式转为attached模式:
bash
docker container attach 容器名

interactive模式
当我们创建好一个容器以后,可能需要去容器内部获取一些信息或者执行一些命令,就需要进入到交互模式。
- 创建容器并且进入交互模式
bash
docker container run -it nginx

- 针对一个已经运行的容器进入到交互模式
bash
docker container run -d -p 80:80 nginx
docker container exec -it 容器名 sh

容器和宿主机内容复制
- 启动一个nginx服务。
bash
docker run --name 容器名 -p 80:80 -d nginx
- 在宿主机上编译一个index.html文件。
bash
mkdir -p /data/mydir/container
cd /data/mydir/container
echo "hello world" > index.html
- 拷贝宿主机文件到容器中。
bash
docker cp /data/mydir/container/index.html 容器名:/usr/share/nginx/html
- 进入容器中查看
bash
cd /usr/share/nginx/html
ls -l

- 从外部页面访问

- 在容器里编辑index.html
bash
echo "after edit" > /usr/share/nginx/html/index.html
- 执行docker cp将内容拷贝到主机上查看,发现文件已经被覆盖

容器自动删除
- 启动一个nginx,指定--rm选项
bash
docker run --name 容器名 -d --rm -p 80:80 nginx
docker ps
- 停止容器
bash
docker stop 容器名

- 再次查看容器是否存在,发现容器自动删除了
bash
docker ps -a

容器自动重启
--启动nginx服务,指定总是重启
bash
docker run --name 容器名 -d -p 80:80 --restart always nginx

- 进入nginx服务,kill启动进程
bash
docker exec -it 容器名 bash
kill 1
- 查看进程状态,可以看到进程还是启动状态
bash
docker ps

- 释放空间
bash
docker stop 容器名
docker rm 容器名
容器环境变量设置
- 启动一个nginx容器,配置环境变量
bash
docker run --name 容器名 -d -p 80:80 -e myenv=1 nginx
- 进入容器查看环境变量
bash
docker exec -it 容器名 bash
env | grep myenv

容器详情查看
- 启动容器
bash
docker run --name test1 -d -p 80:80 -e test1=1 --rm nginx
- 查看容器信息
bash
docker container inspect test1

容器执行单行命令
- 借助docker容器环境执行一些命令,容器中有某个命令而宿主机上没有的时候就可以借助容器完成某一些任务。
bash
docker run --rm -p 80:80 nginx echo "hello world"
- 查看容器,执行完命令后容器自动关闭

样例
制作C++容器
- 下载Ubuntu镜像
bash
docker pull ubuntu:22.04
- 启动容器
bash
docker run --name 容器名 -it ubuntu :22.04 bash
- 在容器里配置镜像源加速
bash
sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g'
/etc/apt/sources.list
- 安装gcc vim
bash
apt update
apt install gcc vim -y
- 编辑+编译代码
bash
mkdir src
cd src
vim test.c
#任意编辑代码
#编译代码
gcc test.c -o test
#运行代码
./test
