1 导论
1.1 容器技术
分为核心技术,平台技术,支持技术
1.1.1 核心技术
包括容器规范,runtime,容器管理工具,容器定义工具(镜像等),registory,容器os等,此处可略
1.1.1.1 容器规范
有两个规范:runtime spec和image format spec
1.1.1.2 runtime
是容器真正运行的地方,可理解为容器所在的context,或者运行容器的地方
有三种runtime:lxc, runc, rkt
lxc:linux老牌runtime
runc:docker自己开发的,也是docker默认的runtime
rkt:coreos开发的
1.1.1.3 容器管理工具:
lxd,docker engine, rkt cli
lxd是lxc的管理工具
docker engine包含daemon和cli
rkt cli是rkt管理工具
1.1.1.4 容器定义工具
有docker image,dockerfile, aci
1.1.1.5 registory
有docker hub, docker registory, quay.io
1.1.1.6 容器os
和runtime区别?容积更小,速度更快,容ios是专门针对容器的
1.1.2 平台技术
有编排引擎,容器管理平台,基于容器的PaaS
1.1.2.1 容器编排引擎
有docker swarm, kubernete,mesos
dockerswarm:docker开发的编排引擎
kubernetes:google开发的,同时支持docker和coreos容器
mesos:通用编排引擎,与marathon一起提供编排功能
1.1.2.2 容器管理平台
rancher, containership
1.1.2.3 基于容器的paas
1.1.3 容器支持技术
有网络,服务发现,监控,数据管理,日志管理,安全等方面
1.2 安装与运行第一个container
1.2.1 安装
安装略,见文章1 ubuntu18 docker配置与安装 镜像加速配置-CSDN博客
1.2.2 运行第一个container:
docker run -d -p 80:80 httpd
2 容器核心技术
2.1 什么是容器
容器与虚拟机区别?容器不需要guest os
2.2 为什么需要容器
集装箱解决多种场景笛卡尔积
2.3 容器如何工作
2.3.1 docker架构
有client,daemon,registory,image, container
docker daemon只能监听本主机,如何监听其他主机
2.3.2 client
2.3.3 server
2.3.4 image
生成镜像方法 1 从无到有创建 2 利用已有镜像生成 3 从registory下载别人的
3 docker镜像
3.1 镜像内部结构
3.1.1 hello-world最小镜像
docker pull hello-world
hello-world docker file如下
FROM scratch
COPY hello /
CMD ["/hello"]
解析
1 scratch 从头开始创建container
2 copy 将dockerfile所在目录的hello文件复制到镜像的/目录下
3 cmd是运行容器时会执行,可被传入cmd参数覆盖
3.1.2 base镜像
以centos为例探索base镜像
docker pull centos
3.1.2.1 用户层和kernel层
centos估计有200mb左右
思考 为啥centos镜像只有200m? os包括用户层和kernel层,容器用的host的kernel层,容器包含的主要是用户层,不同的linux发行版本区别也主要是用户层的不同,/dev, /bin这些都是用户层的东西
3.1.2.2 base镜像提供最小规模的linux发行版
centos docker file如下
FROM scratch
ADD centos-7-docker.tar.xz /
CMD ["/bin/bash"]
3.1.2.3 支持多种linux os
3.1.3 镜像分层结构
举例说明分层特性,看一个docker file,分层特性也可以从docker pull时的output看出
FROM debian
RUN apt-get install emacs
RUN apt-get install apache2
CMD ["/bin/bash"]
流程:镜像一层一层搭,搭完新一层立即删除临时旧image,下次搭层再用上次创的旧iamge
思考 为什么容器cmd总是/bin/bash?
思考 修改容器其他层会影响到其他层吗?不会,容器层由镜像层和最顶的可写层组成,实际改动的是可写层,镜像层是只读的,实际的改动会在writable层记录
思考 多个层如果存在相同路径文件,实际环境的此文件是哪层的?最上层的
3.2 构建镜像
方法:1 docker commit(用已有容器生成新镜像) 2 dockerfile
3.2.1 docker commit
思考 docker建镜像可commit或dockerfile,为什么不推荐commit?无法批量管理与创容器
流程 创一个container -> 安装软件比如vi -> 保存container为新image(docker commit container_id new_image_name)
3.2.2 dockerfile
3.2.2.1 第一个docker file
FROM ubuntu
RUN apu-get update && apt-get install -y vim
思考 第二行为啥不能分两行些?方便还是不能?不能,层的缓存特性会导致新建容器不执行apt-get update,可能出问题
3.2.2.2 查看分层结构
3.2.2.3 image缓存特性
docker 会缓存已有的镜像层,构建镜像时如发现缓存的镜像层,就直接使用,不新建,如果发现新层不一样,就会构建
思考 如何不使用缓存?直接每层都让构建?build后加--no-cache
思考 docker什么时候会用到层缓存特性?构建镜像和下载镜像
3.2.2.4 调试dockerfile
思考 如何调试dockefile? dockerfile创建失败时不会删除上次新创建的imgae层,此时可docker run -it image_id进入容器debug
3.2.2.5 dockerfile常用指令
from maintainer copy add env expose volume workdir rum cmd entrypoint
workdir 进入容器的当前目录位置,如image不存在这个路径会自动创建
3.3 RUN vs CMD vs ENTRYPOINT
3.3.1 shell & exec
思考 为什么推荐使用exec而不是shell?可包含空格等特殊字符
区别:shell默认使用/bin/bash,所以cmd用shell会解析环境变量,但exec默认不使用/bin/bash,不会直接解析环境变量,如需用bash需显示传入
3.3.2 RUN
3.3.3 CMD
dockerfile中的cmd只有最后一个有效;如果docker run传入cmd,则dockerfile中的cmd会被覆盖。如何传入cmd?docker run -it httpd /bin/bash
3.3.4 ENTRYPOINT
每个都会执行,和cmd不同,不会被忽略只保留最后一个
3.4 分发镜像
如何在多个host使用image?1 dockerfile 2 公用repository 3 本地私有repository
3.4.1 为镜像命名
实际不光有名字,还有tag,一般dockerfile build的是latest默认,知识叫latest不代表是最新的tag
docker tag old_tag new_tag_name
3.4.2 使用公共repository
先在docker host登录
docker login -u username
此处仓库的镜像名会用到用户名,所以镜像格式如下:[username]/image:tag,所以如上传,先改名image
如何上传image到共有hub 1 本地登录docker 2 本地改container名,格式为[username]/container:tag 3 docker push [user]/container:tag
3.4.3 本地registry
进步性:1 无需internet 2 docker hub不是全免费 3 安全原因放外网不好
启动:docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:v2
改名,准备将container传到本地registry 名字指的是registry的名字[registry-host]:[port]/user/conta:version
上传镜像 docker push xxx(为上一步改名后的名字)
测试是否可下载镜像 docker pull xxx
3.5 小结
3.5.1 rmi
思考 rmi可以删其他主机和registry 的吗?可以删本host,不可删registry和其他主机的image
思考 一个image有多个tag,什么时候会真正删除image
4 docker容器
4.1 运行容器
4.1.1 如何指定docker启动运行命令
1 cmd 2 entrypoint 3 docker run后追加
4.1.2 长期运行容器
有的容器运行就退出了,如何长期运行?
4.1.2.1 简单粗暴 传入命令无限循环防止退出
docker run ubuntu /bin/bash -c "while true; do sleep 1; done"
会占用一个终端,加 -d后台运行即可
docker创建后分配随机名字,如果想指定container名字,docker run时传入 --name即可
4.1.3 进入容器方法
4.1.3.1 docker attach
docker attach container_id 直接进入container的原终端,不会新开,如果原终端在无限循环,那你啥也干不了
4.1.3.2 docker exec
docker exec -it container_id
4.1.3.3 区别
如上,是否开新终端 docker logs -f container_id可以查看容器启动命令的输出
4.2 stop/start/restart
docker stop container_id
docker kill container_id
docker run -d --restart=[always|on-failure:3]
4.3 pause/unpause
4.4 删除容器
docker rm container_id
也可一次删除多个:docker rm containera_id containerb_id ... 或 docker rm -v $(docker ps -aq -f status=exited)
4.5 state machine状态机
docker run == docker create + docker start
4.6 资源限制
4.6.1 内存限制
docker run -m 200M --memory-swap=300M ubuntu(注意,swap=300-200=100)
docker run -m 200M --memory-swap 300M progirum/stress --vm 1 --vm-bytes 280M
--vm: 一个线程
--vm-bytes: 每个线程分配的内存(vm-bytes比memory-swap小就没事)
4.6.2 cpu限制
docker run --name "containera" -c 1024 --cpu 1
docker run --name "containerb" -c 512 --cpu 1
-c cpu相对优先级,默认为1024
--cpu 设置工作线程数
发生什么:都是一个cpu,所以ps看cpu使用率是66.6,33.3,不会超过100因为一个cpu
4.6.3 block io带宽限制
docker run -it --name "containera" --blkio-weight 500
--blkio-weight 也是相对值
--device-read-bps 限制读某个设备的bps
--device-write-bps
--device-read-iops 限制读某个设备的iops
如何测容器读写速率?进入容器,time dd -if /dev/zero -of test.out bs=1M count=800 oflag=direct
direct,device-read-bps才能生效
4.7 容器底层技术
主要有cgroup和namespace
4.7.1 cgroup
容器的cpu和内存的限额实际是限制cgroup 如--cpu-share -m -c --memory-swap,这些会以配置文件形式存储,路径为/sys/fs/cgroup/cpu/docker,如cpu-share,会在该路径下的文件cpu.share保存,内容是docker run配置的值
4.7.2 namespace
namespace管理host唯一的全局资源,linux有六种namespace,分别为mount,uts,ipc,pid,network和user
uts让容器拥有自己的hostname,ipc会隔离容器的共享内存和信号量
5 docker网络
docker安装时会在host创三种网络:bridge,host,null
docker network ls
网络可通过docker run --network=none指定
5.1 none
该网络没有任何网卡,即封闭环境
5.2 host
如何查看容器网卡信息?进入容器,ip l
host网络,在容器中可以看到host的网卡,且container hostname也是hostname
优点:直接使用host网络,性能好
缺点:缺少灵活性,需要考虑端口冲突等
5.3 bridge
docker安装时在host会创建一个docker0的linux bridge,容器默认网络会挂在到这里
主机brctl show可查看bridge
创完容器brctl show胡覅先docker0 的interface列多了一个vethxxx,是容器的虚拟网卡挂在到docker0了
进入容器 ip a查看容器网络配置,这里配置看到的网卡和brctl show看到的网卡不是一个网卡,他们是一对网卡
思考 如何查看容器的网段?可以看容器挂在的网络的子网:docker network inspect bridge,bridge子网网关默认是docker0
5.4 user-define网络
docker提供三种user-define网络驱动:bridge,overlay,macvlan。
可手动创建bridge:
docker network create --driver bridge my_net
创建网络时可手动指定子网,通过--subnet和--gateway指定
思考 容器从bridge分配的ip都是默认的,是否可以手动分配?可以,通过--ip指定,注意,只有使用--subnet创建的子网才可以指定容器创建的ip,否则报错
不同网络容器默认无法通信,可手动添加不同网络之间通信
docker network connect net container_id
5.5 容器间通信
容器间可通过IP,DNS,join方式通信
5.5.1 ip通信
同一个网络的容器通信实际是ip通信
5.5.2 DNS通信
DNS即ping的时候用container name而不是ip
注意 只能在user-define的网络使用,就是说默认的bridget无法使用dns
注意 不同网络dns也无法通信
5.5.3 joined通信
可以使两个或多个容器共用一个网络栈
docker run -d -it --name=weba httpd
docker run -d -it --network=container:weba busybox
5.6 容器与外部世界连接
5.6.1 容器访问外部
容器默认可以访问容器外部网络,为啥?
5.6.2 外部世界访问容器内部
主要通过端口映射,端口映射通过docker-proxy,每个有端口映射的container都会开一个docker-proxy进程
6 docker存储
主要有两种存储:storage driver和data volume
6.1 storage driver
回顾容器分层特性的可写层:1 对容器的改动均会存到容器可写层 2 修改的数据会从镜像曾复制到可写层,然后修改后存入可写层 3 同名文件只会保留最上层的镜像曾中的文件
driver有很多:AUFS、device mapper 、btrfs、OverlayFS、VFS、ZFS、
用哪个driver?一般用linux发行版 推荐的driver
driver适用于无状态的container,比如busybox,运行时修改的数据会存在可写层,可写层会存在driver,容器没了数据就删了,没有持久化存储
6.2 data volume
volume实际是host的文件,可mount,目前好像无法设置volume大小
6.2.1 bind mount
实质是将host已存在目录或文件mount到容器
-v实现mount,若容器此路径不为空,则路径文件会被藏起来,真是使用的是host mount的文件
docker run -d -v <host_path>:<container_path> container
docker run -d -v /htdocs:/usr/local/apache2/htdocs httpd
注意 容器删除后volume不会被删除,即/htdocs不会被删除
bind mount时还可指定权限:
docker run -d -p 80:80 <host_path>:<container_path>:ro httpd
思考 host mount的路径不存在会发生什么?不存在的路径会被创一个文件夹而不是文件mount给container
局限性:需要显示指定mount的host路径,限制了container移植性
6.2.2 docker managed volume
docker managed volume和bind mount区别是不需要指定host的mount路径,docker会自己找一个目录存container mount的路径,因为docker指定,方便迁移。如果mount point非空,会将东西复制到volume,然后再将volume mount到container
docker run -d -p 80:80 -v <container_path> httpd
docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
docker inspect 发现host mount在/var/lib/docker/volume/container_id/下
docker volume看不到bind mount,只能看到docker managed volume,bind mount得通过docker inspect看
6.3 数据共享
6.3.1bind mount & docker managed volume
bind mount & docker managed volume可以实现数据共享
6.3.2 docker cp
docker cp <host_path> container_id:<container_path>
docker cp container_id:<container_path> <host_path>
6.3.3 容器间数据共享
1 多个container bind mount到一个host path
2 volume container
6.4 volume container
专门为别的容器提供volume的容器,其他容器的volume可以用这个volume container
docker create --name vc_data -v ~/htdocs:/usr/bin/apache2/htdocs -v /other/useful/tools busybox
docker run --name web1 -d -p 80 --volume-from vc_data httpd
特点:
1 不必每次bind mount都显示指定路径,已经由volume container实现了
6.5 data-packed volume container
volume container实质是放在host的,是否有数据完全放在container,给其他容器共享的?
data-packed volume container实际是将mount打包到镜像,然后通过docker managed volume给其他容器i共享
FROM busybox:latest
ADD htdocs /usr/bin/apache2/htdocs
VOLUME /usr/bin/apache2/htdocs
6.6 data volume生命周期管理
主要包括备份、迁移、恢复、销毁volume
6.6.1 备份
如果是本地registry,直接定期备份本地registry目录即可
6.6.2 恢复
同上
6.6.3 迁移
如果registry更新,1 先停掉本地registry容器 2 启动新版本registry容器,把老版本registry volume mount到新版本registry
6.6.4 销毁
容器删除不会删除持久化volume
bind mount删除时不会删除volume;docker managed volume删除时,除非docker rm 时带上-v可以删除volume。如果volume还被其他容器mount,则这个volume也无法删除容器时被删除
常用命令
docker history container_id
docket ps
docker rmi image_id
docker run -it -p 80:80 httpd
docker exec -it ...
docker build -t image_name dockerfile_path
docker tag src_tag_name target_tag_name
docker search
4 docker容器
docker ps -a
docker container ls -a
思考
1.1.1.6 容器os和runtime区别
2.1 容器与虚拟机区别
2.3.1 docker daemon只能监听本主机,如何监听其他主机 /etc/systemd/system/multi-user.target.wants/docker.service,ExecStart环境变量后添加-H tcp://0.0.0.0允许任意ip用户连接
3.1.2 为啥centos镜像只有200m? os包括用户层和kernel层,容器用的host的kernel层,容器包含的主要是用户层,不同的linux发行版本区别也主要是用户层的不同,/dev, /bin这些都是用户层的东西
3.1.2.2 copy add 区别? 如果是归档包,add会直接解压;add支持从url add,copy不支持,
3.1.3 为什么cmd后总是跟/bin/bash?
3.1.3 修改容器其他层会影响到其他层吗?不会,容器层由镜像层和最顶的可写层组成,实际改动的是可写层,镜像层是只读的,实际的改动会在writable层记录
3.1.3 多个层如果存在相同路径文件,实际环境的此文件是哪层的?为啥?最上层的
3.2.1 docker建镜像可commit或dockerfile,为什么不推荐commit?无法批量管理与创容器
3.2.2 第二行为啥不能分两行写?方便还是不能?不能,层的缓存特性会导致新建容器不执行apt-get update,可能出问题,保证apt-get update是最新的
3.2.2.1 思考 如何不使用缓存?直接每层都让构建?build后加--no-cache
3.2.2.3 docker什么时候会用到层缓存特性?构建镜像和下载镜像,push存或更新镜像的的时候
3.2.2.4 如何调试dockefile? dockerfile创建失败时不会删除上次新创建的imgae层,此时可docker run -it image_id进入容器debug
3.3 为什么推荐使用exec而不是shell?可包含空格等特殊字符
3.3.4 cmd和entrypoint区别?1 cmd会被保留仅一个,entrypoint不会,每个都会被执行 2 entrypoint推荐使用,cmd一般用来传入参数,毕竟只能用一次
3.4.2 如何上传image到共有hub 1 本地登录docker 2 本地改container名,格式为[username]/container:tag 3 docker push [user]/container:tag
3.4.2 上传镜像到公共hub会用缓存特性吗?
3.4.2 用registry时注意container名字:公共hub不需要host:port
3.5.1 rmi可以删其他主机和registry 的吗?可以删本host,不可删registry和其他主机的image
3.5.1 一个image有多个tag,什么时候会真正删除image?所有tag都删完的时候
5.2 如何查看容器网卡信息?进入容器,ip l
5.3 如何查看容器的网段?可以看容器挂在的网络的子网:docker network inspect bridge,bridge子网网关默认是docker0
5.4 容器从bridge分配的ip都是默认的,是否可以手动分配?可以,通过--ip指定,注意,只有使用--subnet创建的子网才可以指定容器创建的ip,否则报错
5.4 相同bridget网络容器是否可互通?可互通
5.4 如何实现不同网络容器的通信?需添加容器对某网络的网卡
5.5.2 所有网络都能用dns吗?只有user-define的网络才能用dns
6.2.1 volume是持久化数据,container删除后文件不会被删除
6.2.1 host mount的路径不存在会发生什么?不存在的路径会被创一个文件夹而不是文件mount给container