一、简介
1.docker的意义
- 容器是标准化的软件单元,Docker 将应用程序与该程序的依赖,打包在一个image文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。
- Docker容器映像是一个轻量级,独立的可执行软件包,包含运行应用程序所需的一切:代码,运行时,系统工具,系统库和设置。
- 容器映像在Docker Engine上运行时成为容器,Docker Engine使容器化应用程序能够在任何基础架构上一致地运行。
2.容器和虚拟机的区别
容器是应用层的抽象,它将代码和依赖关系打包在一起。多个容器可以在同一台机器上运行,并与其他容器共享操作系统内核,每个容器在用户空间中作为独立进程运行。容器占用的空间比VM少(容器映像的大小通常为几十MB),可以处理更多的应用程序,并且需要更少的VM和操作系统。
虚拟机(VM)是物理硬件的抽象,将一台服务器转变为多台服务器。管理程序允许多台VM在单台机器上运行。每个VM都包含操作系统的完整副本,应用程序,必要的二进制文件和库 - 占用数十GB。虚拟机也可能很慢启动。
3.基本概念
- 镜像(Image):一个只读模板,带有创建 Docker 容器的说明。
- 容器(container):容器就是镜像的运行实例,负责应用程序的运行,包括操作系统、用户添加的文件以及元数据。它可以被启动、开始、停止、删除。容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。。
- Docker Registry:用来存储 Docker 镜像的仓库,Docker Hub 是 Docker 官方提供的一个公共仓库,而且 Docker 默认也是从 Docker Hub 上查找镜像的。
- Docker客户端(Docker client):命令行工具,用于与Docker后台交互。
- Docker后台(Docker daemon):dockerd,用来监听 Docker API 的请求和管理 Docker 对象,比如镜像、容器、网络和 Volume。
- 底层技术支持:Namespaces(做隔离)、CGroups(做资源限制)、UnionFS(镜像和容器的分层)
二、ubuntu 安装docker社区版
1.先决条件
Support oparation
64-bit version of one of these Ubuntu versions:
- Disco 19.04
- Cosmic 18.10
- Bionic 18.04 (LTS)
- Xenial 16.04 (LTS)
Uninstall old versions
$ sudo apt-get remove docker docker-engine docker.io containerd runc
Supported storage drivers
- Docker Engine - Community on Ubuntu supports
overlay2
,aufs
andbtrfs
storage drivers.- Docker Engine - Community uses the
overlay2
storage driver by default.
- Docker Engine - Community uses the
2.安装docker engine - community
有三种安装方法
- 使用软件源docker repository安装,适合于有网状态
- 使用deb 包安装,适合于无网状态
- 通过脚本安装,适合于测试和开发环境,有风险
1)Install using the repository
配置仓库
# 更新软件源
$ sudo apt-get update
# Install packages to allow apt to use a repository over HTTPS
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# add Docker’s official GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 验证系统拥有指纹数据9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
$ sudo apt-key fingerprint 0EBFCD88
# 添加远程仓库到软件源,稳定版、测试版或轻量版 x86_64/amd64:[arch=amd64], arm64:[arch=arm64],armhf:[arch=armhf]
$ sudo add-apt-repository \
"deb [arch=arm64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
安装docker engine
# 更新软件源 (必须)
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
# 安装特定版本docker
#列出可用版本
$ apt-cache madison docker-ce
# 安装特定版本,比如<VERSION_STRING>可以为 5:18.09.1~3-0~ubuntu-xenial
$ sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
# 验证docker是否安装成功
$ docker --version
$ sudo docker run hello-world
2)Install from a package
下载所需版本的docker https://download.docker.com/linux/ubuntu/dists/
# 安装deb包
$ sudo dpkg -i /path/to/package.deb
# 测试docker
$ docker --version
$ sudo docker run hello-world
3.卸载docker engine - community
$ sudo apt-get purge docker-ce
$ sudo rm -rf /var/lib/docker
三、镜像的操作
1.获取镜像
Docker 运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker 会从镜像仓库下载(默认是 Docker Hub 公共注册服务器中的仓库)。
-
docker search
命令来查找官方仓库中的镜像sudo docker search ubuntu
-
docker pull
命令来从仓库获取所需要的镜像到本地镜像库# 从注册服务器仓库中下载 $ sudo docker pull ubuntu:12.04 # 相当于 $ sudo docker pull registry.hub.docker.com/ubuntu:12.04 命令,即从注册服务器 registry.hub.docker.com 中的 ubuntu 仓库来下载标记为 12.04 的镜像。 # 从其它仓库下载 $ sudo docker pull dl.dockerpool.com:5000/ubuntu:12.04 # 列出本地镜像 $ sudo docker images
2.导出导入镜像
# 从本地镜像库导出到本地文件
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 c4ff7513909d 5 weeks ago 225.4 MB
...
$ sudo docker save -o ubuntu_14.04.tar ubuntu:14.04
# 或
$ sudo docker save ubuntu:14.04 > ubuntu_14.04.tar
# 或
$ sudo docker save ubuntu:14.04 | gzip > ubuntu_14.04.tar.gz
# 导入本地文件到本地镜像库
$ sudo docker load --input ubuntu_14.04.tar #或ubuntu_14.04.tar.gz
# 或
$ sudo docker load -i ubuntu_14.04.tar #或ubuntu_14.04.tar.gz
# 或
$ sudo docker load < ubuntu_14.04.tar #或ubuntu_14.04.tar.gz
3.移除本地镜像
# docker rm 命令是移除容器
$ docker rm [imageName]
# docker rmi 或 docker image rm 命令移除本地的镜像
$ sudo docker rmi training/sinatra
Untagged: training/sinatra:latest
Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0
注意:在删除镜像之前要先用 docker rm
删掉依赖于这个镜像的所有容器。
四、容器的操作
容器是独立运行的一个或一组应用,以及它们的运行态环境。因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
1.创建并启动容器
# docker run运行image文件,每执行一次就会新建一个容器实例
$ sudo docker run ubuntu:14.04 /bin/echo 'Hello world'
Hello world
# 交互模式下启动容器,用户可以通过所创建的终端来输入命令
$ sudo docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#
# -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。
# 守护态运行(后台运行)容器,通过添加 -d 参数来实现
$ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147
# 获取容器的输出信息
$ sudo docker logs insane_babbage
hello world
hello world
...
$ sudo docker ps #查看所有正在运行的容器
$ sudo docker ps -a #查看创建的所有容器
$ sudo docker ps -l #查看最近创建的一个容器
容器启动流程
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
2.启动已创建并终止的容器
# 启动已经生成且已停止运行的容器文件
$ docker start [containerID]
# 交互模式下启动容器
$ docker start -it [containerID] /bin/bash
# 后台启动容器
$ docker start -d [containerID]
# 重启容器
$ docker restart [containID]
3.终止容器
# 停止终止容器实例的运行,向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号。应用程序可以自行进行收尾清理工作
$ docker stop [containerID]
# 强制终止容器实例的运行,直接发出 SIGKILL 信号,有些容器会自动终止
$ docker kill [containID]
4.进入容器
# 进入一个已经启动的容器
$ docker exec -it [containerID] /bin/bash
# 退出容器
exit
5.导入导出容器
# 导出容器到本地容器快照
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7691a814370e ubuntu:14.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
$ sudo docker export 7691a814370e > ubuntu.tar
# 导入本地容器快照到本地镜像库
$ cat ubuntu.tar | sudo docker import - test/ubuntu:v1.0
注意:用户既可以使用 docker load
来导入镜像存储文件到本地镜像库,也可以使用 docker import
来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。
6.移除容器
# docker rm 命令移除容器
$ docker rm [imageName]
五、Docker 的网络模式
1.Bridge模式【默认】
当 Docker 启动时,会自动在主机上创建一个
docker0
虚拟网桥,实际上是 Linux 的一个 bridge。Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给docker0
接口。此后启动的容器内的网口也会自动分配一个同一网段的地址,并设置 docker0 的 IP 地址为容器的默认网关。当创建一个 Docker 容器的时候,同时会创建了一对
veth pair
接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即eth0
;另一端在本地并被挂载到docker0
网桥,名称以veth
开头(例如vethAQI2QT
)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
$ docker run -tid --net=bridge --name docker_bri1 ubuntu-base:v3
$ docker exec -ti docker_bri1
2.Host 模式
如果启动容器的时候使用host
模式,那么这个容器将不会获得一个独立的Network Namespace
,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
$ docker run -tid --net=host --name docker_host1 ubuntu-base:v3
$ docker exec -ti docker_host1 /bin/bash
3.Container 模式
新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
$ docker run -tid --net=container:docker_bri1 --name docker_con1 ubuntu-base:v3
$ docker exec -ti docker_con1 /bin/bash
$ docker exec -ti docker_bri1 /bin/bash
4.None模式
使用none
模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。
$ docker run -tid --net=none --name docker_non1 ubuntu-base:v3
$ docker exec -ti docker_non1 /bin/bash
六、数据共享与持久化
为了能保存容器运行过程中产生的数据,我们使用数据卷来实现持久化。 数据卷可以docker创建,也可以使用主机目录。
数据卷
1)特点
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新,不会影响镜像
- 数据卷默认会一直存在,即使容器被删除
2)操作
# 创建一个数据卷volume
$ docker volume create my-vol
# 查看所有的数据卷volume
$ docker volume ls
DRIVER VOLUME NAME
local 1c3caf57674bd2e7e85511ed41932cc065a2f6c8a00c9f94cb9a70467206fcb4
local 2b7eb2cc385fff0cd8b36abb09a1f4975f3c0c90a9cd0f55e88f09657ce7436a
......
local compose-files_consul-config
......
local my-vol
# 查看指定 数据卷 的信息
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
# 运行image,给容器添加数据卷,并进入容器
docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名 /bin/bash
# 例如 docker run -it -v /src/app:/opt/app centos /bin/bash
# 或docker run -it -v my-vol:/opt/app centos /bin/bash
# 设置只读数据卷
docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
# 只可以在宿主机创建文件,然后共享给容器,但是容器内不允许修改文件
# 删除指定volume
docker volume rm [volume name]
3)数据共享测试
- 容器和宿主机之间数据共享
- 通过在宿主机的环境和容器的环境下,分别操作文件,观察数据是否可以同步
- 容器停止退出后,主机修改后数据是否同步
4)数据卷容器
给容器挂载了数据卷,然后其它容器也可以通过挂载这个容器(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器
docker run -it --name childDoc --volumes-from 77c79cca0420 centos
七、docker常用命令汇总
# 查看docker版本或信息
$ docker version
# 或者
$ docker info
# 查看docker占用磁盘空间
$ docker system df
# 显示容器使用的系统资源
$ docker stats
# 列出本机的所有 image 文件。
$ docker image ls
# 删除 image 文件
$ docker image rm [imageName]
# 运行image文件,每执行一次就会新建一个容器实例
$ docker container run [imageName]
# 运行image文件,并进入容器
$ docker container run -it [imageName] /bin/bash
# 查看所有运行的容器实例
$ docker container ls --all
$ docker ps #查看所有正在运行的容器
$ docker ps -a #查看创建的所有容器
$ docker ps -l #查看最近创建的一个容器
# 启动已经生成且已停止运行的容器文件
$ docker start [containerID]
# 停止终止容器实例的运行,向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号。应用程序可以自行进行收尾清理工作
$ docker stop [containerID]
# 强制终止容器实例的运行,直接发出 SIGKILL 信号,有些容器会自动终止
$ docker kill [containID]
# 进入一个正在运行的容器实例,一旦进入了容器,就可以在容器的 Shell 执行命令
$ docker exec -it [containerID] /bin/bash
# 从正在运行的 Docker 容器里面,将文件拷贝到本机
$ docker cp [containID]:[/path/to/file] .
八、验证linux内核的容器兼容性
如果在自定义系统下安装或运行docker运行出错,则需要确定当前linux的内核配置是否满足docker的要求。
# 例如运行hello-world engine报错
$ docker run hello-world
docker: Error response from daemon: failed to create endpoint focused_kepler on network bridge: failed to add the host (veth801a7b4) <=> sandbox (veth0fbfd2e) pair interfaces: operation not supported.
ERRO[0000] error waiting for container: context canceled
使用check-config.sh脚本检验linux内核的配置项是否满足要求
$ wget https://github.com/moby/moby/raw/master/contrib/check-config.sh
$ chmod +x check-config.sh
$ ./check-config.sh
admin@edgenode:~$ ./check-config.sh
info: reading kernel config from /proc/config.gz ...
Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: missing
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: missing
- CONFIG_BRIDGE: enabled
- CONFIG_BRIDGE_NETFILTER: enabled (as module)
- CONFIG_NF_NAT_IPV4: enabled
- CONFIG_IP_NF_FILTER: enabled
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled
- CONFIG_IP_NF_NAT: enabled
- CONFIG_NF_NAT: enabled
- CONFIG_NF_NAT_NEEDED: enabled
- CONFIG_POSIX_MQUEUE: enabled
- CONFIG_DEVPTS_MULTIPLE_INSTANCES: missing
Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_MEMCG_SWAP: enabled
- CONFIG_MEMCG_SWAP_ENABLED: enabled
(cgroup swap accounting is currently enabled)
- CONFIG_MEMCG_KMEM: enabled
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: enabled
- CONFIG_IOSCHED_CFQ: enabled
- CONFIG_CFQ_GROUP_IOSCHED: enabled
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_NET_CLS_CGROUP: enabled
- CONFIG_CGROUP_NET_PRIO: enabled
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: enabled
- CONFIG_IP_NF_TARGET_REDIRECT: enabled
- CONFIG_IP_VS: enabled
- CONFIG_IP_VS_NFCT: enabled
- CONFIG_IP_VS_PROTO_TCP: enabled
- CONFIG_IP_VS_PROTO_UDP: enabled
- CONFIG_IP_VS_RR: enabled
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: enabled
- Network Drivers:
- "overlay":
- CONFIG_VXLAN: enabled
- CONFIG_BRIDGE_VLAN_FILTERING: enabled
Optional (for encrypted networks):
- CONFIG_CRYPTO: enabled
- CONFIG_CRYPTO_AEAD: enabled
- CONFIG_CRYPTO_GCM: enabled
- CONFIG_CRYPTO_SEQIV: enabled
- CONFIG_CRYPTO_GHASH: enabled
- CONFIG_XFRM: enabled
- CONFIG_XFRM_USER: missing
- CONFIG_XFRM_ALGO: enabled
- CONFIG_INET_ESP: missing
- CONFIG_INET_XFRM_MODE_TRANSPORT: missing
- "ipvlan":
- CONFIG_IPVLAN: enabled
- "macvlan":
- CONFIG_MACVLAN: enabled
- CONFIG_DUMMY: enabled
- "ftp,tftp client in container":
- CONFIG_NF_NAT_FTP: missing
- CONFIG_NF_CONNTRACK_FTP: missing
- CONFIG_NF_NAT_TFTP: missing
- CONFIG_NF_CONNTRACK_TFTP: missing
- Storage Drivers:
- "aufs":
- CONFIG_AUFS_FS: missing
- "btrfs":
- CONFIG_BTRFS_FS: enabled
- CONFIG_BTRFS_FS_POSIX_ACL: enabled
- "devicemapper":
- CONFIG_BLK_DEV_DM: enabled
- CONFIG_DM_THIN_PROVISIONING: enabled
- "overlay":
- CONFIG_OVERLAY_FS: enabled
- "zfs":
- /dev/zfs: missing
- zfs command: missing
- zpool command: missing
Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000