容器存在的前提,是宿主机的LXC技术,它实现了容器的进程隔离和资源限制。而Docker的贡献,根本在于image这种容器实例的格式,实现了容器的易用性、可移植性。
docker Daemon的配置 : /etc/sysconfig/docker
一、检视
检视底层配置
docker inspect <镜像>/<容器名/id>
能检视镜像,或者检视任何状态的容器的底层信息。容器比镜像,能检视更多信息。
检视镜像时,如果本地没有这个镜像,会先拉取。
1. 检视stdout/in/err是否有关联到terminal
# docker inspect --format='{{ .Conifg.AttachStderr}} {{ .Conifg.AttachStdin}} {{ .Conifg.AttachStdout}}' <镜像>/<容器名/id>
false的话,启动bash时要给-t/-a参数/
2. 检视容器运行命令和命令参数
# docker inspect --format='{{ .Conifg.Cmd}} {{ .Conifg.Entrypoint}} ' <镜像>/<容器名/id>
# docker inspect --format='{{ .Args}} {{ .Conifg.Cmd}} ' <容器名/id>
3. 检视容器Exposed的端口、挂在了宿主机哪些目录
# docker inspect --format='{{ .Conifg.ExposedPorts}} {{ .Conifg.Volumes}} ' <镜像>/<容器名/id>
4. 检视容器环境变量、工作目录、hostname
# docker inspect --format='{{ .Conifg.Env}} {{ .Conifg.WorkingDir}} {{ .Conifg.Hostname}} ' <镜像>/<容器名/id>
5. 检视容器的端口map给了宿主机的哪个端口
# docker inspect --format='{{ .HostConifg.PortBindings.$(3).HostIP/HostPort}} ' <容器名/id>
6. 检视容器的fail-restart机制
# docker inspect --format='{{ .HostConifg.RestartPolicy.MaximumRetryCount}} ' <容器名/id>
7. 检视容器FS是否只读、是否是特权容器、是否开放所有端口
# docker inspect --format='{{ .HostConifg.ReadonlyRootfs}} {{ .HostConifg.Privileged}} {{ .HostConifg.PublishAllPorts}} ' <容器名/id>
8. 检视宿主机docker网络接口
# docker inspect --format='{{.NetworkSettings.Bridge}} {{.NetworkSettings.Gateway}}' <容器名/id>
宿主机的docker0接口ip,为容器的网关。
9. 检视容器网络接口
# docker inspect --format='{{.NetworkSettings.IPAddress}} {{.NetworkSettings.MacAddress}}' <容器名/id>
10. 检视容器cpu/mem资源
# docker inspect --format='{{.Config.Cpuset}} {{.Config.CpuShares}} {{.Config.Memory}} {{.Config.MemorySwap}}' <容器名/id>
11. 检视容器的镜像id、容器名字、容器id、log位置
# docker inspect --format='{{.Image}} {{.Name}} {{.Id}} {{.LogPath}}' <容器名/id>
这个log内容,用docker logs 察看
12. 检视容器SELinux文件和进程上下文
# docker inspect --format='{{.MountLabel}} {{.ProcessLabel}}' <容器名/id>
要挂载到容器的宿主机的文件,要先设置SELinux标示为MountLabel,和ProcessLabel一致。用ls -Z 验证
在宿主机上查看符合容器SELinux进程上下文的进程,ps -efz | grep $(12), 就是容器的主进程
或者:
检视到容器的主进程号 , docker inspect --format='{{.State.Pod}}' <容器名/id>
ps -fZp | grep 主进程号,得到容器进程SELinux上下文
同时,ls -Z /var/lib/docker/containers/<container_id>, 得到容器挂在文件的SELinux上下文
两个应该一致。
关联到容器的启动会话terminal
# docker attach <容器名/id>
nsenter-exec实现的
查看宿主机上可见的容器所有进程
# docker top <容器名/id>
镜像变更察看
# docker history <镜像>
从UFS分层的角度,察看当前镜像的构建历史和原因。
容器变更察看
# docker diff <容器名/id>
这个变更是相对启动容器的最近的镜像的。这个命令常用于 dokcer commit 之前,确认容器将生成的新镜像,相对之前一版镜像有什么变化。
关联到容器的启动会话terminal
# docker attach <容器名/id>
二、配置
存储
这里专指容器使用的、挂在自宿主机的存储。不是宿主机上用来存储容器原数据的存储。
这样的存储的使用意义是,把容器变更、保存在容器外部的存储上,代替了提交容器内数据变更为新镜像的办法。
1. 挂载卷:
# docker run -v <宿主机目录>:<容器内目录>:z/Z -name=<datevol> -it/-d <镜像名> [命令] -->:z/:Z是明确更改源目录的SELinux标签,赋予修改挂载卷的权限。大小写的区别是Z不共享,z作数据卷容器。
2. 有一种容器叫数据卷容器
按1的操作:z,就得到了一个”数据卷容器”,叫datavol。它的意义是:在宿主机的源卷,和其他容器间,形成中间层,让其他容器能间接访问修改源卷,及时容器卷停止运行了:
# docker run --volume-from=<datavol> -it/-d -it/-d <镜像名> [命令]
3. 挂载设备:
# docker run -v /dev/<log>:/dev/<log> ...... --> 容器的log发送给宿主机systemd journal。在宿主机上,journalctl -b 能看到。
4. 挂载套接字
# docker run --privileged=true -v /var/run/docker.sock:/var/run/docker.sock ...... --> 在容器内就可以通过宿主机的Docker Daemon的套接字控制入口,来调用Docker命令了。privileged也是控制SELinux标签的。
这个典型用途是:
CI Docker容器 -- 实现容器内持续集成,构建新镜像;
调用特权容器
宿主机上用来存储容器原数据的存储
后端使用device-mapper,实现镜像层的共享。
建议使用外部存储,挂载在宿主机的/var/lib/docker上,实现docker镜像、容器的存储空间的可扩展性。
网络
容器端口的暴露,实际是容器内服务地址的暴露。
两种方向:
1. 暴露给宿主机:
# docker run -p <宿主机socket或宿主机port>:<容器内暴露的port> ...... --> 从宿主机上访问 宿主机socket,就能访问容器内的服务了。比如:
# curl http://宿主机socket
进一步:
可以通过宿主机socket的访问,把容器的服务 暴露给别的宿主机上的容器。这不是Docker的管理范围了。
当不同服务被期待开放在同一个端口宿主机的时候,需要先把提供服务的容器端口映射到不同宿主机端口,在宿主机上进行外部访问的端口动态映射。
2. 暴露给其他的容器,实现了容器的连接:
# docker run --link=<服务源容器名字>:<自定义连接名字> ...... --> 从这个容器内访问 服务源容器的socket,或者连接名字,就能访问源容器的服务了。比如:
# curl http://服务源容器名字:port curl http://服务源容器ip:port
# curl http://自定义连接名字
只能实现同一个宿主机上的容器连接,因为连接是通过本地的docker0桥接的。
改变容器的网络模式
# docker run --net=<option> ......
option: bridge 默认
none 无网络
othercontainer 重用其他容器的网络栈
host 使用宿主机网络栈。效能最好,但有端口冲突的限制