Docker 基础
为什么需要docker?在传统部署下,我们会遇到不同机器、不同依赖版本的兼容性等问题,解决此问题一般会消耗大量时间,并且在不同机器上均要执行统一环境的部署也是一个耗时较长的工作。除此之外、还包括例如管理Dev/Test/Prod等不同环境的成本。为了解决这些问题,Docker应运而出。
Docker 可以使用不同的Container 运行不同的组件(如node.js web server, MongoDB, Messaging System等),并且这些Containers 可以运行在同一个物理主机上,而相互之间无影响(也就是各有各的执行环境与依赖)。如:
通过上图我们可以看到,Docker Container 是共享的一个Kernel,且执行在Docker 层之上。Docker与Hypervisor(虚拟化中的控制进程)不一样的是:Docker并不是虚拟化,并不是在同一个底层硬件上运行不同的Kernel以及OS,它主要的目的是将应用容器化,使用同一套Kernel与OS执行不同的应用。而传统的虚拟化架构为:
这种虚拟化的架构会很大程度上使用硬件资源,且VM 镜像一般是GB级别的数据。而Docker Container 是一种轻量化的资源,大小也是MB 级别的量。这样可以使得Docker Container 启动更快,一般是秒级别。而VM 启动时间会长的多,因为需要启动整个OS。
Docker 安装与启动
在Linux 下,可以使用 yum 或是 apt-get 直接安装,如:
sudo yum install -y docker
然后启动:
sudo /etc/init.d/docker start
测试:
sudo docker run hello-world
基本Docker 命令
docker run
执行一个docker container,指定参数为image 名,如果本地不存在此image,则会从dockerhub进行下载,例如:
> sudo docker run ubuntu
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
7ddbc47eeb70: Pull complete
c1bbdc448b72: Pull complete
8c3b70e39044: Pull complete
45d437916d57: Pull complete
Digest: sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d
Status: Downloaded newer image for ubuntu:latest
docker ps
列出当前运行的containers。可以使用 docker ps –a 查看所有containers 状态。
docker stop <container_name>
停止一个docker container。但是此 docker container 仍可以被 docker ps -a 命令列出。
docker rm <container_name>
移除一个docker container。
docker images
列出所有images。
docker rmi <image_name>
移除一个image。移除前必须要删除所有正在使用此image 的container。
docker pull <image>
拉取一个 image到本地,之后执行docker run 后,不会再去DockerHub 拉取镜像。
docker exec <command>
在一个docker container 内执行指定命令。如(7e2290cbe2f7为docker id):
docker exec 7e2290cbe2f7 cat /etc/*release*
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
…
Docker Run 命令进阶
1. 指定image 的版本,如:
docker run ubuntu:17.04
2. attach 到一个正在运行的container中,如:
> docker run -d training/webapp
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fdd161c7d3f3 training/webapp "python app.py" 19 seconds ago Up 19 seconds 5000/tcp vibrant_hermann
> docker attach eager_johnson
attach 用于将container 的输出指向当前实例的stdout
3. docker run -i 指定等待stdin 输入
4. 端口映射
在执行一个 web app 样例后,我们可以看到以下输出:
docker run training/webapp
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
此时,这个5000 端口绑定的是一个私网 ip ,例如:我们看一下这个container 内部的 ip:
> docker exec da16b96211f6 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1186 (1.1 KB) TX bytes:0 (0.0 B)
可以看到此 ip 为 172.17.0.2,而我们宿主实例的 ip 为10.0.0.83。所以,若是单纯的使用宿主实例的 ip:5000,是访问不到这个页面的。这里我们需要做端口映射,例如:
docker run -p 80:5000 training/webapp
并且可以启动多个container,使用不同的端口映射,例如:
docker run -p 8000:5000 training/webapp
这样我们便部署了两个 web server,监听的端口分别为外部实例的 8000 端口已经 80 端口。
4. 卷映射
Docker container 内部有自己的文件系统,与外部文件系统隔离。我们也可以将外部卷与docker container 内的卷进行映射。这样在container 销毁后,卷里的数据仍保存在本地。例如:
docker run –v /opt/datadir/:/var/lib/mysql mysql