第一课:docker基本知识
1.什么是docker
使用最广泛的开源容器引擎
一种操作系统级的虚拟化技术
依赖于linux内核特性:namespace和cgroups
一种简单的应用程序打包工具
2.docker的设计目标
提供简单的应用程序打包工具
开发人员和运维人员职责逻辑分离
多环境保持一致性
3.docker的基本组成
docker client 客户端
docker daemon 守护进程
docker images 镜像
docker container 容器
docker registry 镜像仓库
4.容器vs虚拟机
container | VM | |
---|---|---|
启动速度 | 秒级 | 分钟级 |
运行性能 | 接近原生 | 5%左右损耗 |
磁盘占用 | MB | GB |
数量 | 成百上千 | 一般几十台 |
隔离性 | 进程级别 | 系统级(更彻底) |
操作系统 | 只支持linux | 几乎所有 |
封装程度 | 只打包项目代码和依赖关系,共享宿主机内核 | 完整的操作系统 |
5.什么是镜像
一个分层存储的文件
一个软件的环境
一个镜像可以创建N个容器
一种标准化的交付
一个不包含linux内核而又精简的linux操作系统
镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <ID/NAME>查看镜像中各层内容及大小,每层对应着dockerfile中的一条指令。docker镜像默认存储在/var/lib/docker/\<storage-driver\>中。
6.镜像从哪里来
Docker Hub是由docker公司负责维护的公共注册中心,包含大量的容器镜像,docker工具默认从这个公共镜像库下载镜像。地址:https://hub.docker.com/explore
配置镜像加速器:https://www.daocloud.io/mirror
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
7.镜像与容器的联系
容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时,会先从镜像里要协议的文件复制到容器自己的文件系统中(读写层)。
如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高磁盘利用率。
若想持久化这些改动,可以通过docker commit将容器保存成一个新镜像
8.docker镜像常用命令
指令 | 描述 |
---|---|
ls | 列出镜像 |
build | 构建镜像来自Dockerfile |
inspect | 显示一个或多个镜像详细信息 |
pull | 从镜像仓库拉取镜像 |
push | 推送一个镜像到镜像仓库 |
rm | 移除一个或多个镜像 |
prune | 移除未使用的镜像。没有被标记或被任何容器引用的 |
tag | 创建一个引用源镜像标记目标镜像 |
export | 导出镜像文件系统到tar归档文件 |
import | 导入镜像文件系统tar归档文件创建镜像 |
save | 保存 一个或多个镜像到一个tar归档文件 |
load | 加载镜像来自tar归档或标准输入 |
9.容器管理
9.1创建容器常用选项
选项 | 描述 |
---|---|
-i,nteractive | 交互式 |
-t,tty | 分配一个伪终端 |
-d,detach | 运行容器到后台 |
-e,env | 设置环境变量 |
-p,publish list | 发布容器端口到主机 |
-P,publist-all | 发布容器所有EXPOSE的端口到宿主机的随机端口 |
-name string | 制定容器名称 |
-h,hostname | 设置容器主机名 |
-ip string | 制定容器IP,只能用于自定义网络 |
-network | 连接容器到一个网络 |
-mount mount | 将文件系统挂在到容器 |
-v,-volume list | 绑定挂载一个卷 |
-restart string | 容器退出时重启策略,默认no,可选值[always|no-failure] |
9.2容器资源限制
选项 | 描述 |
---|---|
-m,-memory | 容器可以使用的最大内存量 |
-memory-swap | 允许交换到磁盘的内存量 |
-memory-swappiness=<0-100> | 容器使用swap分区交换的百分比(0-100,默认为-1) |
-oom-kill-disable | 禁用oom killer |
-cpus | 可以使用的CPU数量 |
-cpuset-cpus | 限制容器使用特定的CPU核心,如(0-3,0,1) |
-cpu-shares | CPU共享(相对权重) |
示例:
内存限额
允许容器最多使用500M内存和100M的swap,并禁用oom killer。
docker run -itd --name web03 --memory=500m --memory-swap=600m -oom-kill-disable -P nginx
CPU限额:
允许容器最多使用一个半的CPU:
docker run -itd --name web01 --cpus="1.5" nginx
允许容器最多使用50%的CPU:
docker run -itd --name web01 --cpus=".5" nginx
9.3管理容器常用命令
选项 | 描述 |
---|---|
ls | 列出容器 |
inspect | 查看一个或多个容器详细信息 |
exec | 在运行容器中执行命令 |
commit | 创建一个新镜像来自一个容器 |
cp | 拷贝文件/文件夹到一个容器 |
logs | 获取一个容器日志 |
port | 列出或指定容器端口映射 |
top | 显示一个容器运行的进程 |
stats | 显示容器资源使用统计 |
stop/start | 停止/启动一个或多个容器 |
rm | 删除一个或多个容器 |
10.管理应用程序数据
10.1 将数据从宿主机挂载到容器中的三种方式
docker提供三种方式将数据从宿主机挂载到容器中:
volume:docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
bind mount:将宿主机上的任意位置的文件或者目录挂载到容器中。
tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统内。如果不系统将数据持久存储在任何位置,可以使用tmpfs,同时避免写入容器可写层提高性能。
10.2 volume
管理卷:
docker volume create nginx-vol
docker volume ls
docker volume inspect nginx-vol
用卷创建一个容器:
docker run -itd --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
docker run -itd --name=nginx-test -v nginx-vol:/usr/share/nginx/html ngin
清理:
docker stop nginx-test
docker rm nginx-test
docker volume rm nginx-vol
注意:
1.如果没有指定卷,自动创建。
2.建议使用--mount,更通用。
10.3 bind mount
用卷创建一个容器:
docker run -itd --name=nginx-test --mount type=bind,src=/app/wwwwroot,dst=/usr/share/nginx/html nginx
docker run -itd --name=nginx-test -v /app/wwwroot:/usr/share/nginx/html nginx
验证绑定:
docker inspect nginx-test
清理:
docker stop nginx-test
docker rm nginx-test
注意:
1.如果源文件/目录不存在,不会自动创建,会抛出一个错误
2.如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏
10.4 小结
volume特点:
- 多个运行容器之间共享数据。
- 当容器停止或被移除时,该卷依然存在。
- 多个容器可以同时挂载相同的卷。
- 当明确删除卷时,卷才会被删除。
- 将容器的数据存储在远程主机或其他存储上。
- 将数据从有台docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/volumes/)
bind mount特点: - 从主机共享配置文件到容器。默认情况下,挂载主机/etc/resolv.conf到每个容器,提供DNS解析。
- 在docker主机上的开发环境和容器之间共享源代码。例如,可以将Maven target目录挂载到容器中,每次在docker主机上构建maven项目时,容器都可以访问构建的项目包。
- 当docker主机的文件或目录结构保证与容器所需的绑定挂载一致时。
11.docker四种网络模式
bridge
-net=bridge
默认网络,docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。
host
-net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个,这就意味着容器不会有自己的网卡信息,而是使用宿主机的, 容器除了网络,其他都是隔离的。
none
-net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
container
-net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
自定义网络
与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。
12.docker网络管理
桥接宿主机网络与配置固定IP地址
临时生效:
#网桥名称
br_name=br0
#添加网桥
brctl addbr $br_name
#给网桥配置IP
ip addr add 192.168.1.120/24 dev $br_name
#删除已存在的eth0网卡配置
ip addr del 192.168.1.120/24 dev eth0
#激活网桥
ip link set $br_name up
#添加eth0到网桥
brctl addif $br_name eth0
#添加路由
ip route add default via 192.168.1.1 dev br0
还需要在docker启动时桥接这个网桥
#vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -b=br0
#systemctl restart docker
永久生效:
vi /etc/sysconcig/network-scripts/ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
BRIDGE=br0
vi /etc/sysconfig/network-scripts/ifcfg-br0
DEVICE=br0
TYPE=Bridge
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.1.120
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
配置固定IP
C_ID=$(docker run -it --net=none ubuntu)
C_PID=$(docker inspect -f '{{.State.Pid}}' $C_ID)
#创建network namespace目录并将容器的network namespace软连接到此目录,以便ip netns命令读取
mkdir -p /var/run/netns
ln -s /proc/$C_PID/ns/net /var/run/netns/$C_PID
#添加虚拟网卡veth+容器PID,类型是veth pair,名称是vp+容器PID
ip link add veth$C_PID type veth peer name vp$C_PID
#添加虚拟网卡到br0网桥
brctl addif br0 veth$C_PID
#激活虚拟网卡
ip link set veth$C_PID up
#设置容器网络信息
IP='192.168.1.123/24'
GW='192.168.1.1'
#给进程配置一个network namespace
ip link set vp$C_PID netns $C_PID
#在容器进程里面设置网卡信息
ip netns exec $C_PID ip link set dev vp$C_PID name eth0
ip netns exec $C_PID ip link set eth0 up
ip netns exec $C_PID ip addr add $IP dev eth0
ip netns exec $C_PID ip route add default via $GW
pipework工具配置容器固定IP
git clone https://github.com/jpetazzo/pipework.git
cp pipework/pipework /usr/local/bin
docker run -itd --net=none --name test01 ubuntu
pipework br0 test01 192.168.1.88/24@192.168.1.1