官网地址
学习视频(上)
学习视频(下)
Docker 概念
什么是 Docker ?
- Docker 是一个用于开发、发布和运行程序的开放平台
- Docker 能够将应用程序与基础架构分离,以便可以快速交付软件
- 使用 Docker,可以像管理应用程序一样管理基础架构
- 通过 docker 命令快速发布、测试和部署代码
- 使用 docker 可以将打包代码和所需环境一起封装到一个集装箱
- 运行这个箱子便能一键部署环境
Docker 历史与发展
- 起源(Golang):2010年,美国成立的一家小公司
docCloud
。主要做一些PaaS
的云计算服务,LXC
有关的容器技术。后来他们将自己的容器技术命名为Docker
,但是当时并没有引起行业的注意
- 开源(
源码地址
):为了生存,这家公司在2013年将 Docker 开源,每个月更新一个版本,2014年4月9日,1.0发布。然后越来越多人发现它好用,慢慢火起来!
- 发展:现在,越来越多的公司使用 Docker 搭建和部署项目生产环境(不论是私有云、公有云、还是混合云)
Docker 架构
镜像(Images)
容器(Container)
- 通过运行镜像可以创建一个实例运行,该实例称为容器
- 一个镜像可以创建多个容器
- 可以对容器进行额外的操作,这些操作会被迭代,然后可以提交为新的镜像
仓库(Repository)
- 所有镜像存放在仓库里,包括本地仓库和远程仓库
- 远程下载(pull)的镜像和本地提交(commit)的镜像会保存在本地仓库,本地仓库的镜像可以推送(push)到远程仓库
守护进程(Daemon | Dockerd)
- 接收客户端的指令,处理 docker 内部和远程仓库的资源
Docker 工作流程
相关名词解释及概念
容器技术(LXC)与虚拟机技术(VM)
容器技术与虚拟机技术都属于虚拟化技术,只是虚拟对象不同
- 将计算机硬件(包括CPU、内存、磁盘空间、网络适配器等)虚拟化,抽象、转换成一台或多台电脑的可分割、可组合配置环境
- 优点是虚拟出来的计算机像真实机器一样运行程序与软件实现
- 缺点是过于笨重,资源利用率没有发挥到极致,不可跨平台,启动慢等
- 将操作系统内核虚拟化,利用 linux 核心中的资源分离机制和 namespaces,创建独立的容器,在单一linux实体下运行,无视基础设施的差异部署到任何一个地方
- 容器实例运行在独立隔离的环境里,不需要虚拟机一样需要庞大的虚拟化类库
- 因此具有轻巧、资源高利用率、易部署、跨平台等特点
容器与镜像
安全性争议
2021年,安全公司Palo Alto Networks研究人员Aviv Sasson,在Docker Hub上发现的恶意容器映像档,分别来自10个不同账号,总下载次数超过2000万次,其中内含的挖矿软件
Docker 基础使用
安装
官方安装文档(linux、windows、macOS)
1
2
3
4
5
6
7
8
9
|
# 国外源(速度慢)
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 阿里源
sudo yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
|
基本命令
官网全部命令
帮助命令
1
2
3
4
5
6
7
8
|
# docker 版本信息
$ docker version
# docker 系统信息
$ docker info
# 查看 docker 所有命令
$ docker [command] --help
|
镜像命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# 查看所有镜像
$ docker images
$ docker images -a
$ docker images -aq
# 搜索远程仓库镜像
$ docker search mysql
$ docker search mysql --filter=STARS=500
# 下载镜像(默认 latest)
$ docker pull mysql
$ docker pull mysql:5.7
# 删除本地镜像
$ docker rmi 4181d485f650
$ docker rmi -f mysql:5.7
# 将一个容器制作为一个镜像
$ docker commit [可选参数] <id|container> <newImageName>[:tag]
-a 作者
-m 注释
-p 暂停当前容器
-c 使用 Dockerfile 指令创建镜像
# 将镜像提交到 docker hub
# 1. 标记为自己的镜像
$ docker tag <image[:tag]> <username>/<image[:tag]>
# 2. 提交
$ docker push <username>/<image[:tag]>
|
容器命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# 新建容器并启动
$ docker run --name="nginx" -d -it -p 8080:80 nginx
$docker run [可选参数] <Image>
--name="Name" 容器名
-d 后台方式运行(如果没有前台使用,自动停止)
-it 交互方式运行(进入容器查看内容)
-v 卷挂载
-e 配置环境
-p 端口映射
主机端口:容器端口
容器端口
-P 随机指定端口
# 容器中退回主机并停止(ctrl+p+q 退出不停止)
$ exit
# 显示正在运行的容器
$ docker ps
# 显示所有的容器
$ docker ps -a
# 删除容器
$ docker rm <id|container>
$ docker ps -a -q|xargs docker rm
$ docker container prune # 删除所有停止运行的镜像
# 启动和停止容器
$ docker start <id|container>
$ docker restart <id|container>
$ docker stop <id|container>
$ docker kill <id|container>
# 进入容器并操作
$ docker exec -it <id|container> /bin/bash
# 进入容器查看运行终端
$ docker attach <id|container>
# 将容器内文件拷贝到主机
$ docker cp CONTAINER:SRC_PATH HOST_PATH
# 将主机文件拷贝到容器内
$ docker cp HOST_PATH CONTAINER:SRC_PATH
|
其他命令
1
2
3
4
5
6
7
8
|
# 查看日志
$ docker logs <id|container> [可选参数]
-f 列出所有
-n 限定行数
-t 显示时间
# 查看元数据
$ docker inspect <image|container|network|...>
|
Docker 进阶
镜像原理
联合文件系统和分层迭代
- Docker 采用 AUFS(advanced muti-layerd unifaction filesystem,高级多层统一文件系统),可以实现联合挂载
- 具体表现是可以如 git 一样对容器和镜像进行版本迭代,每新增一个镜像或操作
- 因此,添加镜像时,分为多个包批量拉取,如果是本地镜像已有的部分,将会复用
- 当镜像完全下载好后,多层文件会被压缩为一层
- 如下:
容器数据卷
将 docker 内部的文件挂载到本机,实现本地可以操作 docker 内部数据,实现数据持久化
命令挂载
1
2
3
4
5
6
|
$ docker run -d -p 3310:3306 -v /mysql5.7/conf:/etc/mysql/conf.d -v /mysql5.7/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql5.7_01 mysql:5.7
# windows
$ docker run -d -p 3310:3306 -v H:\Docker\mysql5.7\conf:/etc/mysql/conf.d -v H:\Docker\mysql5.7\data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql5.7_01 mysql:5.7
$ docker run --name ipsec-vpn-server --env-file ./vpn.env --restart=always -v ikev2-vpn-data:/etc/ipsec.d -v /lib/modules:/lib/modules:ro -p 500:500/udp -p 4500:4500/udp -d --privileged hwdsl2/ipsec-vpn-server
|
docker inspect mysql5.7_01
查看卷挂载
挂载分类
1
2
3
4
5
6
7
8
9
10
11
12
|
# 匿名挂载
$ docker run --name <name> -P -d -v /etc/nginx <image>
# 具名挂载
$ docker run --name <name> -P -d -v nginx_volume:/etc/nginx <image>
# 指定路径挂载
$ docker run --name <name> -P -d -v /data/nginx:/etc/nginx <image>
# 其中,具名和匿名挂载可通过以下方式查找路径
$ docker volume ls # 产看所有挂载卷
$ docker volume inspect <volume> # 查看指定挂载卷的元数据
|
Dockerfile
Dockerfile 是一个脚本文件,可以通过这个文件创建 docker 镜像
1
2
3
4
5
6
|
# 通过 Dockerfile 文件创建镜像,最后有个 .
$ docker build [可选参数] .
-t 指定 name:tag
-f 指定 Dockerfile 文件路径。可省略,默认找当前目录下 Dockerfile
-o 输出镜像文件路径
-q 创建成功打印镜像id
|
1
2
3
4
|
# 通过 .dockerignore 忽略文件
*/temp* # 忽略根目录下一级目录所有含 temp 的文件
*/*/temp* # 忽略根目录下二级目录所有含 temp 的文件
temp? # ? 匹配一个字符
|
1
2
3
4
5
|
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
|
Dockerfile 指令
1
2
3
|
# 指定该镜像的基本镜像
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
|
1
2
3
4
|
# 运行一个操作系统命令,然后提交一个新镜像,作为下一次迭代的基本镜像
# 如果是 windows,将 /bin/bash -c 替换为 cmd /S /C
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
RUN ["/bin/bash", "-c", "echo hello"]
|
1
2
3
4
|
# 执行一个命令,只有最后一个生效,且 docker run 指定的时候会被替代
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"] # 默认,作为 ENTRYPOINT
CMD ["executable", "param1", "param2"]
|
1
2
3
|
# 与 CMD 类似,但会一个一个追加,且不会被 RUN 替代
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
|
1
2
|
MAINTAINER <name>
# 使用 LABEL org.opencontainers.image.authors="SvenDowideit@email" 替代
|
1
2
|
# 端口映射
EXPOSE EXPOSE 80/tcp EXPOSE 80/udp
|
1
2
|
# 设置环境变量
ENV ENV <key>=<value> ...
|
1
2
3
4
5
|
# 添加文件到镜像指定位置,可以是使用通配符?和*,可多个
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
ADD hom* /mydir/
ADD hom?.txt /mydir/
|
1
2
3
|
# 复制文件到镜像指定位置,可以是使用通配符?和*,可多个
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
|
1
2
3
|
# 在镜像中创建一个或多个挂载点,可以将镜像作为数据卷容器共享数据
# 如果是 windows ,需要写成 windows 的文件目录形式
VOLUME VOLUME ["/data",...]
|
1
2
3
|
# 设置用户及分组,类似于 windows 的用户和分组
USER <user>[:<group>]
USER <UID>[:<GID>]
|
1
2
|
# 运行容器后进入容器的工作目录,默认是根目录
WORKDIR /path/to/workdir
|
1
2
3
4
|
# 定义了一个变量
# 用户可以使用--build-arg <varname>=<value>标志在构建时使用 docker build 命令将该变量传递给构建器
# 如果用户指定了未在 Dockerfile 中定义的生成参数,则生成将输出警告
ARG ARG <name>[=<default value>]
|
1
2
3
|
# 向镜像添加了一个触发器指令,该指令将在以后用作另一个生成的基础时执行
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
|
1
2
3
|
# 设置将发送到容器以退出的系统调用信号,镜像默认的停止信号将会被重写
# 因此 docker run 和 docker create 时需要指定参数 --stop-signal
STOPSIGNAL signal
|
1
2
3
|
# 健康检查,默认值:--interval=30s --timeout=30s --start-period=0s --retries=3
HEALTHCHECK [options] CMD command
HEALTHCHECK NONE
|
1
2
3
4
|
# 指定执行命令行的 shell 程序
SHELL ["executable", "parameters"]
SHELL ["powershell", "-command"]
SHELL ["cmd", "/S", "/C"]
|
Example
1
2
3
4
5
6
|
FROM centos
ENV MYPATH=/user/local
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD /bin/bash
|
1
2
3
4
5
|
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
|
Docker 命令总结
Docker 高级
Docker 网络
1
2
3
4
5
6
7
8
|
# 查看所有 docker 网络,默认有3个
# 1、bridge 桥接(默认)
# 2、host 和主机共享
# 3、none 不配置
$ docker network ls
# 查看网络元数据
$ docker network inspect <network>
|
- Docker 中所有的网络都是虚拟的
- Docker 一运行就会创建一个网络,该网络以
桥接
的方式连接所有内部运行容器的网络
- Docker 内运行一个容器便会生成一对
evth-pair
网络,该网络默认会加到默认的桥接网络
- 默认情况下只能以地址方式 ping 通,但是通过
docker run --name <container1> --link <container2> <image>
可以通过容器名单向 ping通(不推荐)
- 使用自定义创建桥接网络可以实现以容器名 ping 通,原理是向容器元数据中添加了 ip 映射
自定义网络连通
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
### 同个网络下 ping 通
---------------------------
# 1. 创建一个桥接网络
$ docker network create --driver bridge --subnet 172.168.0.0/16 --gateway 172.168.0.1 mynet
# 2. 运行容器并加入自定义网络
$ docker run -d -P --name nginx01 --net mynet nginx
$ docker run -d -P --name nginx02 --net mynet nginx
# 3.进入其中一个容器并 ping 另一个容器
$ docker exec -it nginx01 ping nginx02
### 不同网络下 ping 通
-------------------------------
# 1. 启动一个容器到默认网络
$ docker run -d -P --name nginx03 nginx
# 2. 加入自定义桥接网络
$ docker network connect mynet
|
Docker Compose
- 什么是 Docker Compose?
- Compose 是一个定义和运行多容器 Docker 应用程序的工具
- 使用 YAML 文件配置应用程序服务
- 使用单个命令创建、启动所有服务
- 如何使用?
Dockerfile
文件定义应用环境
docker-compose.yml
定义组成应用的服务
docker compose up
命令运行
-
安装 Compose
(windows和mac桌面版默认安装了)
.env 环境变量文件
如果你的 docker-compose.yml
文件需要使用变量,需要创建一个.env
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
version: '3.8'
services:
web:
image: "webapp:${TAG}"
build: .
# $$ 转义一个 $
# command: "$$VAR_NOT_INTERPOLATED_BY_COMPOSE"
# 控制服务启动顺序
command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"]
# 指定一些环境变量
environment:
- DEBUG=1
env_file:
- .env.dev
db:
image: "postgres:${POSTGRES_VERSION}"
frontend:
image: frontend
profiles: ["frontend"]
phpmyadmin:
image: phpmyadmin
depends_on:
- db
profiles:
- debug
backend:
image: backend
|
docker-compose --env-file ./config/.env.dev up
启动时指定环境变量文件
docker-compose --env-file ./config/.env.dev config
重写默认启动文件
- 如上
- DEBUG=1
运行时将会转化为docker run -e DEBUG=1
- 如上
- web-variables.env
运行时将会转化为docker run --env-file=.env.dev
- 如上设置了
profile
属性的服务默认情况下不启动,docker-compose run phpmyadmin
显示指定时启动(不会启动db
),或docker-compose --profile frontend --profile debug
才启动
- YAML 文件支持不同环境的重写,如
docker-compose.prod.yml
继承默认的docker-compose.yml
- 使用 Compose 默认会自动创建一个网络,所有的服务启动会创建一个和服务名一样的网络并加入
开发环境到生产环境
- 移除所有程序代码的卷绑定
- 绑定主机与容器的端口映射
- 配置生产环境的变量
- 重新启动策略
- 额外的生产环境服务
因此可以创建一个docker-compose.prod.yml
配置生产环境,然后两个配置文件一起启动:docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
YAML 文件的配置
官方相信配置文档
案例:搭建WordPress博客
- 创建一个项目目录
WordPress
- 进入该目录
cd WordPress
- 创建YAML文件
docker-compose.yml
,并配置
- 启动
docker-compose up -d
- 浏览器访问
http://localhost:8000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
version: "3.9"
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- wordpress_data:/var/www/html
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
wordpress_data: {}
|
Docker Swarm(已废弃)
用于 docker 集群的部署
现使用 Kubernetes
替代,
官方文档
Kubernetes(k8s)