Docker基础
一、Docker架构
Docker的基本组成包括Docker客户端、Docker守护进程、Docker镜像和Docker容器,为客户端-服务器(C/S)架构。涉及以下概念:
- 镜像(Image):Docker镜像是Docker的构建基块,它是一个轻量级、可移植的打包格式,包含了应用程序及其依赖,以及Docker运行时需要的配置和元数据。Docker镜像可以通过Dockerfile定义,并可以上传到Docker仓库分享给其他用户使用。
- 容器(Container):Docker容器是基于Docker镜像创建的运行实例,它是一个隔离的用户空间,包括一个完整的文件系统、进程空间和网络空间。Docker容器可以通过Docker客户端创建、启动、停止、删除等操作。
- 仓库(Repository):存放镜像的仓库,用于对镜像进行版本控制。
- Docker守护进程(Daemon):Docker守护进程是Docker的核心组件,它负责管理Docker的资源,包括Docker镜像、Docker容器、Docker网络等。Docker守护进程提供了一个RESTful API,使得用户可以通过Docker客户端远程管理Docker守护进程。运行在操作系统上的一个服务。
- Docker客户端(Client):Docker客户端是用户与Docker交互的命令行工具,它提供了一系列命令来创建、管理和操作Docker镜像和容器。通过命令行(Docker CLI)或其他工具使用Docker SDK与Docker守护进程(daemon)进行通信。
- Docker主机(Host):物理机或虚拟机,用于执行Docker守护进程和容器。
- 命名空间(Namespace):Docker使用命名空间隔离了容器的进程、网络、文件系统等,保证了容器内的进程和资源与宿主机的进程和资源隔离。
- 控制组(Cgroup):Docker使用控制组限制了容器的资源使用,包括CPU、内存、磁盘等,保证了容器的资源隔离和限制。
- 联合文件系统(UnionFS):Docker使用联合文件系统将应用程序及其依赖打包成一个镜像,容器运行时则以只读方式挂载该镜像并在其上面创建一个可写的层,保证了容器的可移植性和隔离性。
二、Docker容器
基础命令
- Docker客户端
$ docker
$ docker stats --help
- 获取镜像
$ docker search nginx;
$ docker pull nginx:latest
- 启动、后台运行、停止和进入
# 启动镜像,并以命令行模式进入该容器
$ docker run -it nginx /bin/bash
# 后台运行
$ docker run -itd nginx /bin/bash
# 进入一个后台运行的容器
$ docker exec -it <容器ID> /bin/bash
# 停止一个正在运行的容器
$ docker stop <容器ID>
# 重启一个正在运行的容器
$ docker restart <容器ID>
# 启动一个终止的容器
$ docker start <容器ID>
# 导出某个容器到本地
$ docker export <容器ID> > nginx.tar
# 从容器快照文件中导入镜像
$ cat nginx.tar | docker import - nginx:v1
# 指定URL或目录导入镜像
$ docker import <url> <镜像名>
# 删除一个处于终止状态的容器
$ docker rm -f <容器ID>
# 清理所有处于终止状态的容器
$ docker container prune
web应用
以training/webapp为例示范运行Web应用
# 拉取镜像
$ docker pull training/webapp
# 后台启动容器
$ docker run -d -P training/webapp python app.py
# 查看正在运行的容器,获取本机映射端口
$ docker ps
$ docker port <容器ID/容器名>
# 请求本机对应端口,访问web应用
$ curl http://localhost:32769
# 查看web应用程序日志
$ docker logs -f <容器ID>
# 查看web应用程序的进程
$ docker top <容器ID>
# 停止web应用容器
$ docker stop <容器ID>
# 启动一个终止状态的容器
$ docker start <容器ID>
# 删除终止状态的容器
$ docker rm <容器ID>
三、Docker镜像
创建镜像
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
- 更改已创建的容器来创建镜像,并提交该镜像;
- 使用 Dockerfile 指令来创建新的镜像。
四、Docker容器连接
网络端口映射
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。
- -P :是容器内部端口随机映射到主机的端口;
- -p : 是容器内部端口绑定到指定的主机端口,如:
$ docker run -d -p 1234:5000 training/webapp python app.py
指定容器内部5000端口绑定到主机的1234端口。
Docker容器互联
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
新建网络
$ docker network create -d bridge test-net
连接容器
- 创建容器container1并连接到test-net;
$ docker run -itd --name container1 --network test-net ubuntu /bin/bash
- 创建容器container2并连接到test-net。
$ docker run -itd --name container2 --network test-net ubuntu /bin/bash
验证连接
若container1或container2中无ping命令,则先安装:
$ apt-get update
$ apt install iputils-ping
- container1中 ping container2
$ docker exec -it container1 /bin/bash
/ ping container2
- container2中 ping container1
$ docker exec -it container2 /bin/bash
/ ping container1
配置DNS
宿主机上配置全部容器的DNS
- 在宿主机的 /etc/docker/daemon.json 文件中(若/etc下无docker/目录,手动新增目录及文件)增加以下格式的内容来设置全部容器的 DNS(下述示例设定容器DNS为14.114.114.114 和 8.8.8.8):
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}
- 重启docker
$ sudo systemctl restart docekr
- 查看容器的 DNS 是否生效:
$ docker run -it --rm ubuntu cat etc/resolv.conf
手动指定容器的DNS
如果只想在指定的容器设置 DNS,则可以使用以下命令:
$ docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
参数说明:
- –rm:容器退出时自动清理容器内部的文件系统。
- -h HOSTNAME 或者 --hostname=HOSTNAME: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts。
- –dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。
- –dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。
- 如果在容器启动时没有指定 --dns 和 --dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。
五、Dockerfile
定制镜像
FROM 和 RUN 指令:
- FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx;
- RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
- shell 格式:
RUN <命令行命令> # <命令行命令> 等同于,在终端操作的 shell 命令
- exec 格式:
RUN ["可执行文件", "参数1", "参数2"] # RUN ["./test.php", "dev", "offline"] # 等价于 RUN ./test.php dev offline
** 注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大!**
例如:
$ FROM centos
$ RUN yum -y install wget
$ RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
$ RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
构建镜像
在 Dockerfile 文件的存放目录下,执行构建动作:
$ docker build -t nginx:v3 .
上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
常见指令说明
- FROM:构建镜像基于哪个镜像
- MAINTAINER:镜像维护者姓名或邮箱地址
- RUN:构建镜像时运行的指令
- CMD:运行容器时执行的shell环境
- VOLUME:指定容器挂载点到宿主机自动生成的目录或其他容器
- USER:为RUN、CMD、和 ENTRYPOINT 执行命令指定运行用户
- WORKDIR:为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
- HEALTHCHECH:健康检查
- ARG:构建时指定的一些参数
- EXPOSE:声明容器的服务端口(仅仅是声明)
- ENV:设置容器环境变量
- ADD:拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
- COPY:拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能
- ENTRYPOINT:运行容器时执行的shell命令
六、Docker Compose
Compose用于定义和运行多容器Docker应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
docker-compose.yml 的配置案例如下:
# yaml 配置实例
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
安装
- 使用curl下载Docker Compose的二进制包。
# 安装不同版本的替换"v2.15.1"
$ sudo curl -L "https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
参数中使用 uname命令获取系统内核关信息,在linux-x86_64机器上执行,上述命令相当于:
$ sudo curl -L "https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
uname命令来自于英文词组”Unix name“的缩写,其功能是用于查看系统主机名、内核及硬件架构等信息。如果不加任何参数,默认仅显示系统内核名称,相当于-s参数。
语法格式:uname [参数]
常用参数:
-a 显示系统所有相关信息,显示的信息依次为:内核名称,主机名称,内核发行版本号,内核版本,硬件架构,处理器类型,硬件平台类型,操作系统名称
-m 显示计算机硬件架构
-n 显示主机名称
-r 显示内核发行版本号
-s 显示内核名称
-v 显示内核版本
-p 显示主机处理器类型
-o 显示操作系统名称
-i 显示硬件平台类型
参考资料:https://www.linuxcool.com/uname
- 使用chmod命令赋予下载的二进制文件 ”可执行权限“:
$ sudo chmod +x /usr/local/bin/docker-compose
Docker Compose使用实例
1. 准备需要发布的应用(以app.py为例)
a. 创建测试目录
$ mkdir compose_test
$ cd compose_test
b. 新建app.py(需要发布的应用),填充如下内容
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
c. 创建 “requirements.txt”,内容如下:
flask
redis
2. 创建Dockerfile文件
在compose_test目录下,创建一个名为Dockerfile的文件,内容如下:
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]
3. 创建docker-compose.yml
在compose_test目录下,创建一个名为Dockerfile的文件,内容如下:
# yaml 配置
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
4. 使用Compose命令构建和运行应用
在compose_test目录下,执行如下命令启动应用程序
$ docker-composer up -d
5. 验证
a. 使用“docker ps”命令查看容器状态,发现容器已成功运行,绑定主机5000端口
b. 使用**curl**命令访问主机5000端口来访问成功部署的应用程序,发现返回结果符合预期