docker笔记
docker
开源项目:诞生于2013年,dotCloud公司内部的业余项目,Go语言实现
集装箱:目标是实现轻量级的操作系统虚拟化方案,让用户不需要通过关心容器的管理,使得操作更加简便
docker和虚拟机/传统虚拟化的区别:
- 传统的虚拟机:在硬件层实现虚拟化的
- docker:在操作系统层面实现虚拟化,直接复用本地主机的操作系统
为什么要使用docker?
与传统虚拟化方式相比容器相比具有众多的优势
- docker容器启动在秒级
- docker对系统的利用率高,一台主机可以同时运行数千个docker容器
- docker基本不消耗系统资源,使得运行在docker里面的应用的性能很高
其他优势
更快速的支付和部署,开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码
更高效的虚拟化,dicker容器的运行不需要额外的支持,它是内核级的虚拟化,因此可以实现更高的性能
更轻松的迁移和扩展:docker几乎可以在任意平台运行,比如物理机,虚拟机,公有云,私有云,个人电脑,服务器等
更简单的管理:使用docker只需要简单的修改,就可以替代以往大量的更新工作,所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理
特性 容器 虚拟机
启动 秒级 分钟级
硬盘的使用 一般MB 一般GB
性能 接近原生 弱于
系统支持量 单机支持若干上千个容器 一般几十个
docker中的基本概念:
- 镜像(images):只读的模板,镜像可以用来创建容器
- 容器(container):是使用镜像创建并运行的实例,可以简单的将容器看做是启动了的简化版的操作系统(可以看作是操作系统是因为里面包含root用户权限,进程空间,用户空间和网络空间,还包括运行在里面的应用程序)
- 仓库(repository):集中存放镜像文件的地方,分为公有仓库和私有仓库
yum
yum provides ifconfig //查询ifconfig这个命令来自哪个服务(压缩包)
docker:
拉取镜像
docker pull images-name
查看当前系统中存在的镜像
docker images
docker命令选项
- -i:可以交互输入
- -t:打开伪终端
- -d:后台运行
启动/停止容器运行
docker start/stop container-ID
导出已有的镜像到本地
docker save -o centos.tar centos
导入已有的镜像
docker load --input centos.tar
删除容器
docker rm container-ID
删除多个容器
docker rm -f container-ID container-ID
删除所有容器
docker rm $(docker ps -a -q)
删除镜像
docker rmi images-name
搜索公共镜像
docker search images-name
进入正在运行的容器
docker attach container-ID
更改镜像名称:
docker tag container-ID 新的名称:标签
指定名称
docker run -it --name 名称 centos /bin/bash
create:创建容器,
run:运行容器
pause:挂机/暂停容器
unpause:取消暂停,继续运行容器
stop:发送sigterm停止容器
kill:发送sigkill快速停止容器
exec:在容器中启动新进程,通常需要使用“-it”参数
logs:显示容器启动进程的控制台输出,使用“-f”持续打印
rm:从磁盘删除容器
创建容器
1、通过基础镜像创建镜像,然后添加功能生成镜像
docker commit -m net-tools -a Shuai dbd37da37fed net-tools/centos:v2
- -m:指定提交的描述信息
- -a:指定镜像作者
- dbd37da37fed:用来创建镜像的容器ID
- net-tools/centos:指定要创建的目标镜像名
- v2:指定镜像的TAG
[root@localhost ~]# docker commit -m net-tools -a Shuai dbd37da37fed net-tools/centos:v2
sha256:0073383914bf1d80a29c27628aebd09a63dee998ca0c00b0a6ae1224cd5f84ec
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
net-tools/centos v2 0073383914bf 6 seconds ago 300MB
ubuntu latest ea4c82dcd15a 4 weeks ago 85.8MB
centos latest 75835a67d134 5 weeks ago 200MB
[root@localhost ~]# docker run -it 0073383914bf
[root@6cd3891004eb /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.4 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:04 txqueuelen 0 (Ethernet)
RX packets 6 bytes 508 (508.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2、通过docker build命令,通过dockfile文件的方式,生成镜像
关于镜像
1.分层
最小的镜像:hello-world
FROM scratch
scratch:指定/说明当前镜像搜索从0开始构建的镜像
COPY hello /
复制hello到根目录中
CMD ["/hello"]
执行hello
FROM 镜像名称(通常base镜像,基础镜像)
bash镜像:通常就是Linux的不同发行版本,构成用户空间,不依赖其他镜像,其他镜像用它扩展
1、从0开始的镜像,不依赖与其他镜像
2、通常包含Linux不同的发行版本
3、没有其他的软件程序在其中
系统各个层级之间的耦合关系:
普通虚拟化和容器虚拟化的区别:
解除耦合:
解耦 半解耦
docker的核心概念之:namespace
目的是docker有独立的ip,端口,路由等,隔离作用
六项隔离:
- 主机名和域名: UTS
- 信号量,消息列队和共享内存: IPC
- 进程编号: PID
- 网络设备,网络栈,端口等: network
- 挂载点: mount
- 用户和组: user
可以直接在文件系统中查看指向不同的namespace号的文件
ls -l /proc/##/ns
Linux内核实现namespace主要目的是为了实现轻量级虚拟化此容器服务,在同一个nameserver下的进程可以彼此感知,而对外界的进程一无所知。在这种情况下,让容器中的进程产生错觉,仿佛自己置身于一个独立的系统环境,以此实现独立和隔离的目的
docker的核心概念之:cgroups
不仅可以将被namespace隔离的资源进行设置权重,计算使用量,操作进程启动停止等
是Linux内核提供的一种机制,可以根据特定的行为,把一系列的系统任务以及子任务整合/分离到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架
可以限制,记录,隔离进程组所使用的物理资源(包括CPU,内存,IO等),为容器实现虚拟化提供了基本保证,是构建docker等一系列虚拟化管理工具的基础
cgroups的作用:
实现cgoups的主要目的是为不同用户层面的资源管理,提供一个统一化的接口,从单个进程的资源控制到操作系统层面的虚拟化
提供四大功能:
- 资源限制:cgoups可以对进程组使用的资源总额进行限制,比如设置应用运行时内存的上限,超出则发出警告
- 优先级分配:通过分配的cpu时间片数量以及硬盘IO带宽大小,实际上就是相当于控制了进程运行的优先级
- 资源统计:cgroups可以统计系统资源使用量,比如CPU使用时间,内存使用量等,适用于按量计费
镜像仓库
如何将自己创建的镜像进行共享
Dockerfile,共享该文件:需要传输文件,然后对方自己再次build
将镜像上传到公共的registry,其他主机直接下载
搭建私有的registry,只能给本地的docker host使用
镜像的命名:[images name] = [REPOSITORY] : [TAG]
运行容器:
docker run centos
两种方式进入容器:attach和exec
说明如下:
- -it 以交互模式打开,执行bash,其结果就是打开了一个bash终端
- 进入到容器中,容器的hostname 就是其"短ID"
- 可以像在普通Linux中一样执行命令。ps -elf显示了容器启动进程 while 以及当前的 bash 进程
- 执行 exit 退出容器,回到docker host。docker exec -it
bash|sh 是执行exec最常用的方式
attach 与 exec的主要区别
attach 直接进入容器,启动命令的终端,不会启动新的容器
如果想直接在终端中查看启动命令的输出,用attach;其他情况使用exec
如果只是为了查看启动命令的输出,可以使用docker logs 命令
docker logs -f container-ID
容器运行相关的知识点:
- 当CMD 或 docker run命令行指定的命令运行结束时,容器停止
- 通过-d参数在后台运行
- 通过exec -it 可以进入容器并执行命令
指定容器的三种方式
- 短ID
- 长ID
- 容器名称。可通过 --name 为容器重命名
docker start
容器可能会因某种错误而停止运行,对于服务类容器,我们通常希望在这种情况下容器能够自动重启,启动容器时设置 --restart 就可以达到这个效果。
--restart=always 意味着无论容器因何种原因退出(包括正常退出),就立即重启,该参数的形式还可以是 --restart=on-failure:3 意思是如果启动进程退出代码非0,则重启容器,最多重启3次
内存限额:
容器内存包括两部分:物理内存和swap
在docker中可通过参数控制容器内存的使用量:
-m 或 --memory:设置内存的使用限额
--memory-swap:设置内存+swap的使用限额
<strong><span style="color: #000000;">指定该容器最多使用200M内存和100M的swap</span></strong>
docker run -it -m 200M --memory-swap=300M centos
默认情况下,两组参数值为1。表示对容器的内存和swap不限制
docker run -it -m 200M --memory-swap 300M progrium/stress --vm 1 --vm-bytes 280
vm 1:启动一个内存工作线程
--vm-bytes 280M:每个线程分配内存280M
限制容器使用CPU:
需要通过-c或者--cpu-shares设置容器使用CPU的权重。如果不指定则默认为1024
限制容器使用CPU取决于CPU share占所有容器CPU share总和的比例
限制容器的Block IO
磁盘的读写
docker中可以通过设置权重,限制bps和iops的方式控制容器读写磁盘的带宽
bps:每秒读写的数据量(byte per second)
iops:每秒IO的次数 (io per second )
默认情况下,所有容器都能够平等的读写磁盘。可以通过--blkio-weight参数改变容器blockIO的优先级
- –-device-read-bps:限制读取某个设备的bps
- –-device-write-bps:限制写入某个设备的bps
- –-device-read-iops:限制读取某个设备的iops
- –-device-write-iops:限制写入某个设备的iops
- --blkio-weight:优先级,权重值
[root@localhost ~]# docker run -it --name testA --device-write-bps /dev/sda:30MB centos
[root@b0b1e003e11e /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
800+0 records in
800+0 records out
838860800 bytes (839 MB) copied, 26.7244 s, 31.4 MB/s
real 0m26.757s
user 0m0.002s
sys 0m3.482s
对比不限速
[root@localhost ~]# docker run -it --name testB centos
[root@7011f4487e71 /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
800+0 records in
800+0 records out
838860800 bytes (839 MB) copied, 13.0204 s, 64.4 MB/s
real 0m13.024s
user 0m0.014s
sys 0m12.043s
cgroup和namespace
cgroup:实现资源限额
namespace:空间隔离
每个容器会认为自己有一块独立的网卡,即使host上只有一块物理网卡。这样让容器看上去更像是一个独立的计算机
- 主机名和域名: UTS
- 信号量,消息列队和共享内存: IPC //让容器拥有自己的共享和信号量,来实现进程间的通信,而不会与host和其他的容器的ipc混淆
- 进程编号: PID
- 网络设备,网络栈,端口等: network
- 挂载点: mount
- 用户和组: user
docker run -h myhost -it centos
指定容器的主机名
ps axf
//可以看到所有进程的相关信息,包括container的进程信息
docker run -h myhost -it centos
ps axf //只能看到容器内,自己本身的进程信息
//容器中拥有自己的一套PID,这就是PID namespace提供的功能
user namespace:让容器可以管理自己的用户,而host是不能看到容器中创建的用户的
docker 网络
[root@localhost ~]# docker network ls
NETWORKID NAME DRIVER SCOPE
a12b893f6e9b bridge bridge local
cf3f312b5f34 host host local
c7a91b209139 none null local
none网络:什么都没有的网络
docker run -it --network=none busybox
该网络只有lo网络内容,是一个封闭网络
作用:封闭意味着隔离,一些对安全性要求很高并且不需要联网的应用,就可以使用none网络。随机码的生成
host网络:连接到host网络的容器共享Dockerhost的网络栈,容器的网络配置与host完全一样。容器中可以看到host的所有网卡,并且hostname也是host的
作用:使用场景
性能好。网络传输效率得到最大的保留,如果容器对网络传输效率有高要求的话,可以选择host网络
缺点:不灵活,需要考虑端口冲突的问题
bridge网络:桥接
/ # ip l
/ # brctl show
/ # ip a
[root@localhost ~]# ifconfig docker0
[root@localhost ~]# docker network inspect bridge
自定义桥接网络
docker提供了三种user-defined网络驱动:bridge,overlay和macvlan
overlay和macvlan用于创建主机网络
通过bridge驱动创建类似默认的bridge网络:
docker network create --driver bridge my_net
brctl show
容器之间的连通
第一步:开启本地路由转发
第二部:设置容器添加新的网络连接
docker network connect container-name/ID container-name/ID
第三部:使用ping测试
查看docker网卡: docker network ls
查看docker IP: ip a
查看bridge 网卡: brctl show
查看bridge网卡配置:docker network inspect 指定网卡名
创建 bridge网卡: docker network create - - bridge 新建网卡名
(可增添选项 :- -subnet 指定网卡的网段 - -gateway 指定网卡指定的网关址)
删除网卡:docker network rm 指定网卡名
指定网卡来创建容器: docker run -itd --network=网卡名 镜像名
(可增添选项 :--ip 指定容器的IP , 要求是:使用的网卡是 - -subnet 创建的)
添加网卡到指定容器中: docker network connect 指定的网卡 指定的容器名/id
查看防火墙的信息; iptables-save
容器之间的通信方式
三种方式进行通信
IP:容器之间使用同一个网络的网卡,那么他们就可以使用ip进行交互
//不灵活。虽然能够满足通信需求,但是在完成部署前,无法确定IP地址,需要在部署之后才能够指定访问的IP地址
docker DNS server:直接通过容器名称进行通信。有一个要求:必须通过自定义网络才可以相互访问
joined容器:使两个或多个容器共享一个网络栈,共享网卡和配置信息
[root@localhost ~]# docker run -itd --name=web1 httpd
[root@localhost ~]# docker run -it --network=container:web1 --name=web3 busybox
实际使用场景:
- 不同容器中的程序需要通过loopback高效快速的通信,比如web-server和app-server
- 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。
容器与外部世界的通信:
容器访问外部世界
外部世界访问容器
容器访问外部世界:
容器默认是可以访问外网
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
//如果网桥docker0收到来自127.0.0/16网卡的外出包,把该数据交给MASQUERADE处理,而MASQUERADE的处理方式是将包的原地址替换成host的地址转发出去,即做了一次地址转换
外部世界访问容器:端口映射
docker可以将对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器,容器在启动的时候通过-p提供参数映射端口
docker run -itd -p 80 --name web1 httpd //通过-p选项映射端口参数
docker ps -a //查看映射到host的端口
docker port web1 //查看映射到host的端口
curl http://
docker存储
docker为容器提供了两种存储数据的资源
Data volume:
对于整个镜像/容器环境
- 新数据直接存放在最上面的容器层
- 修改现有数据,先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,而镜像层数据保持不变
- 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。以上功能的实现,是基于Docker storage driver的存放数据资源方式,管理镜像层和容器层 docker支持多种storage driver:AUFS,Device Mapper,Btrfs,overlayFS,VFS等。他们都可以实现分层的架构,并且各自有不同的特性。docker在安装时会根据当前系统的配置选择默认的driver,而默认driver具有最好的稳定性 Ubuntu:AUFS,extfs redhat/centos:overlay2,xfs SUSE:Btrfs
持久化存储:
Data volume:本质上是Docker Host文件系统中的目录或文件,能够直接被mount到容器的文件系统中。
特点:
- Data volume是目录或文件,并不是没有格式化的磁盘(块设备)
- 容器可以读写volume中的数据
- volume数据可以被永久的保存,即使使用它的容器已经销毁
对于数据层存储和volume都可以用来存储数据,那么对于实际场景,应该如何选择:
- Database软件 VS Database数据
- web应用 VS 应用产生的日志
- 数据分析软件 VS input/output数据
- Apache server VS 静态的HTML文件
前面的内容应该放在数据层中:应为这部分的内容是无状态的,应该作为镜像的一部分
后面的内容应该放在Data Volume中,因为这部分是需要持久化的数据,应该与镜像分开存放
在docker中提供了两种volume类型:bind mount 和 docker manged volume
bind mount:将host上已经存在的目录或文件mount到容器。默认挂载到容器中目录,容器对其中的文件是具有可读可写权限的。当然,可以通过设置,让容器对文件只读。
使用bind mount单个文件的场景:只需要向容器添加文件,不希望覆盖整个目录
优点:直观高效,易于理解
缺点:不灵活,限制了容器的可移植性
docker manged volume
与bind mount在使用上的区别:不需要指定mount源,直指定mount point即可
两种data volume的对比:
相同点:都是host文件系统中的某个路径(与容器进行交互的)
不同点:
bind mount docker manged volume
volume位置 任意指定 /var/lib/docker/volumes/...
对现有mount
point的影响 隐藏并替换为volume 复制原有数据到volume
是否支持单个文件 支持 不支持,只能是目录
权限控制 可修改 均为读写权限,无控制
移植性 移植性弱 移植性强
容器和容器之间的数据 共享
volume container:给其他容器提供volume容器。并且它提供的卷可以是bind mout,也可以是docker manged volume
使用volume container的特点
与bind mount相比,不需要为每个容器都指定host path,所有路径都在vc当中定义好了,容器只需要与vc关联,实现了容器和host的解耦
使用vc的容器,他们的mount point都是一致的,有利于配置的规范和标准化,当然,也会有一定的局限性
构建镜像
data-pack
FROM busybox:latest
ADD htdocs /usr/local/apache2/htdocs //ADD:将指定的
VOLUME /usr/local/apache2/htdocs
容器能够正确的读取volume中的数据,datapacked镜像中内容是自包含的,不依赖host来提供数据,所以具有很强的可移植性,所以,非常适合
只是静态数据的场景,比如:应用的配置信息,web server的静态文件
volume:创建,共享,使用
volume:备份,恢复,迁移,销毁
备份:
将镜像文件存放到/images目录中,然后定期备份该目录
恢复:
如果数据发生了损坏,直接将之前备份的数据拷贝到/imagess中就可以了
迁移:
首先停止registry容器,然后启动新版本容器并且mount原来的volume
注意:在启动新容器之间需要确保新版本的默认数据路径是否发生变化
删除/销毁
删除需谨慎。volume删除后的数据,是无法找回的
docker不会销毁bind mount,host负责删除数据的。如果想要删除volume,需要在删除容器是添加-v参数,则会将volume一并删除,前提是没有其他容器使用该volume,为了保证数据的安全
在删除容器同时删除volume:
docker rm -v vc_data //容器必须停止运行
如果在删除容器时,没有使用-v选项,则会产生volume,那么可以使用命令查看系统中的所有volume
docker volume ls
然后进行删除操作
docker volume rm volume-name
如果确定当前环境中所有volume都没有被使用,可以进行批量删除
docker volume rm $(docker volume ls -q)
关于docker单主机存储总结
- docker为容器提供的存储资源:storage volume和data volume
- storage volume是用来对镜像层和容器进行管理的
- data volume包括:bind mount 和 docker mangeed volume
- bind mount实现了容器和host之间,容器和容器之间的数据共享
- volume container是就有良好可移植性的容器间的数据共享方式,尤其是镜像化:data-packe volume container
- 关于volume的备份,恢复,迁移,销毁
跨主机容器网络
macvlan:linux kernel模块,网卡的 虚拟化技术
跨主机容器访问
网卡的虚拟化技术:macvlan:linux kernel模块。
开启网卡的混杂模式:
[root@localhost ~]# ip link show ens33
2:
ens33:
<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
link/ether 00:0c:29:be:e8:34 brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip link set ens33 promisc on
[root@localhost ~]# ip link show ens33
2: ens33: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
link/ether 00:0c:29:be:e8:34 brd ff:ff:ff:ff:ff:ff
两台都进行这个操作:
[root@localhost ~]# docker network create -d macvlan --subnet=172.16.86.0/24 --gateway=172.16.86.1 -o parent=ens33 mac_net1
f9478fb945582b5b022fc35dc241b484417a98fb561b93c0fc80f08ab20cf1a1
两台都进行这个操作,启动容器,另一台名字要变
[root@localhost ~]# docker run -itd --name bbox1 --ip=172.16.86.10 ==network mac_net1 busybox
Docker network ls
Brctl show
通过以上查看结果发现:macvlan 不依赖linux bridge
在容器中使用ip a
查看网卡信息,会发现,容器eth0就是通过macvlan虚拟出来的与host主机ens33进行连接的。
添加(装载)一个模块
[roo t@localhost ~]# modprobe 8021q
[root@localhost ~]# modinfo 8021q
filename: /lib/modules/3.10.0-514.el7.x86_64/kernel/net/8021q/8021q.ko
version: 1.8
license: GPL
alias: rtnl-link-vlan
rhelversion: 7.3
srcversion: 7E3D79395FFBC56AFC109DE
depends: mrp,garp
intree: Y
vermagic: 3.10.0-514.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: D4:88:63:A7:C1:6F:CC:27:41:23:E6:29:8F:74:F0:57:AF:19:FC:54
sig_hashalgo: sha256
macvlan:网络的联通和隔离完全依赖VLAN,IP,subnet和路由,docker本身不做任何限制,用户可以像管理传统VLAN网络那样管理macvlan
firewall
- drop:丢弃所有进入的包,而不会出任何回应
- block:拒绝所有外部发起的链接,允许内部发起的链接
- public:允许指定的进入链接
- external:同public,处理伪装的进入链接,一般用于路由转发
- dmz:允许受限制的进入链接
- work:允许受信任的计算机被限制的进入链接
- home:同work,如果流量和ssh,dhcpv6-clinet等服务相关,则允许
- internal:同work,范围针对所有互联网用户
- trusted:信任所有链接