docker
1、概念
1.1、基本概念
Docker本身是一个容器运行载体或称之为管理引擎。我们把引用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例
比较Docker和传统虚拟化方式的不同之处:
1.传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需要应用进程;
2.容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便;
3.每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源
1.2、Docker组成
们发现在安装docker时,不仅会安装docker engine与docker cli工具,而且还会安装containerd,这是为什么呢?
Docker最初是一个单体引擎,主要负责容器镜像的制作、上传、拉取及容器的运行及管理。随着容器技术的繁荣发展,为了促进容器技术相关的规范生成和Docker自身项目的发展,Docker将单体引擎拆分为三部分,分别为runC、containerd和dockerd
其中:
- runC主要负责容器的运行和生命周期的管理(即低层运行时)
- containerd主要负责容器镜像的下载和解压等镜像管理功能(即高层运行时)
- dockerd主要负责提供镜像制作、上传等功能同时提供容器存储和网络的映射功能,同时也是Docker服务器端的守护进程,用来响应Docker客户端(命令行CLI工具)发来的各种容器、镜像管理的任务。
Docker公司将runC捐献给了OCI,将containerd捐献给了CNCF,剩下的dockerd作为Docker运行时由Docker公司自己维护。
2、Docker的安装
关于Docker版本:
Docker-ce Docker社区版,主要用于个人开发者测试使用,免费版本
Docker-ee Docker企业版,主要用于为企业开发及应用部署使用,收费版本,免费试用一个月,2020年因国际政治原因曾一度限制中国企业使用。
安装环境:CentOS 7.3+
1、如果之前安装了旧版docker,请先删除。
1 | sudo yum remove docker \ |
2、安装仓库
1 | sudo yum install -y yum-utils |
3、安装docker engine
1 | sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin |
4、启动docker,运行hello world,查看是否成功
1 | sudo systemctl start docker |
5、配置国内镜像仓库地址
新建/etc/docker/daemon.json文件,输入如下内容:
1 | { |
6、然后重启,配置开机启动
1 | systemctl restart docker |
3、docker run开箱即用
3.1、docker架构
registry 镜像仓库
registry可以理解为镜像仓库,用于保存docker image。
Docker Hub 是docker官方的镜像仓库,docker命令默认从docker hub中拉取镜像。我们也可以搭建自己的镜像仓库。
image 镜像
image可以理解为一个只读的应用模板。image包含了应用程序及其所需要的依赖环境,例如可执行文件、环境变量、初始化脚本、启动命令等。
container 容器
容器是image的一个运行实例。当我们运行一个image,就创建了一个容器。
3.2、docker pull拉取镜像
从镜像仓库拉取镜像到本地
1 | docker pull nginx 不写默认是latest |
一般不建议使用latest,因为最新的镜像是滚动更新的,过一段时间,可能跟你本地的不是同一个。
使用docker images命令查看本地镜像
3.3、docker run命令
docker run [可选参数] 镜像名:版本 []
1、公开端口(-P)
1 | docker run --name some-nginx -d -p 8080:80 nginx:1.22 |
2、后台运行
1 | docker run --name db-mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 |
使用run命令,部署mysql,docker先去本地查找镜像,如果找不到,就去docker hub中拉取镜像
–name 定义容器的名称
-e 声明环境变量
-d容器在后台运行
1 | 查看运行ip |
3、前台交互运行
创建一个新的容器,使用mysql客户端
1 | docker run -it --rm mysql:5.7 mysql -h172.17.0.2 -uroot -p |
-it 使用交互模式,可以在控制台里输入、输出
–rm在容器退出时自动删除容器。一般在使用客户端程序时使用此参数。
如果每次使用客户端都创建一个新的容器,这样将占用大量的系统空间。
mysql -h172.17.0.2 -uroot -p表示启动容器时执行的命令。
1 | docker exec在运行的容器中执行命令,一般配合-it参数使用交互模式 |
3.4、常用命令
1 | 查看正在运行的容器 |
4、Docker网络
4.1、默认网络
docker会自动创建三个网络,bridge,host,none
1、bridge桥接网络
如果不指定,新创建的容器默认将连接到bridge网络。
默认情况下,使用bridge网络,宿主机可以ping通容器ip,容器中也能ping通宿主机。
容器之间只能通过 IP 地址相互访问,由于容器的ip会随着启动顺序发生变化,因此不推荐使用ip访问。
2、host
慎用,可能会有安全问题。
容器与宿主机共享网络,不需要映射端口即可通过宿主机IP访问。(-p选项会被忽略)
主机模式网络可用于优化性能,在容器需要处理大量端口的情况下,它不需要网络地址转换 (NAT),并且不会为每个端口创建“用户空间代理”。
3、none
禁用容器中所用网络,在启动容器时使用
4.2、用户自定义网络
创建用户自定义网络
1 | docker network create my-net |
将已有容器连接到此网络
1 | docker network connect my-net db-mysql |
创建容器时指定网络
1 | docker run -it --rm --network my-net mysql:5.7 mysql -h**db-mysql** -uroot -p |
在用户自定义网络上,容器之间可以通过容器名进行访问。
用户自定义网络使用 Docker 的嵌入式 DNS 服务器将容器名解析成 IP。
5、docker存储
将数据存储在容器中,一旦容器被删除,数据也会被删除。同时也会使容器变得越来越大,不方便恢复和迁移。
将数据存储到容器之外,这样删除容器也不会丢失数据。一旦容器故障,我们可以重新创建一个容器,将数据挂载到容器里,就可以快速的恢复
5.1、挂载绑定(bind mount)
绑定挂载可以将主机文件系统上目录或文件装载到容器中,但是主机上的非 Docker 进程可以修改它们,同时在容器中也可以更改主机文件系统,包括创建、修改或删除文件或目录,使用不当,可能会带来安全隐患
绑定挂载适用以下场景:
- 将配置文件从主机共享到容器。
- 在 Docker 主机上的开发环境和容器之间共享源代码或编译目录。
- 例如,可以将 Maven 的
target/
目录挂载到容器中,每次在主机上用 Maven打包项目时,容器内都可以使用新编译的程序包
1、-V
绑定挂载将主机上的目录或者文件装载到容器中。绑定挂载会覆盖容器中的目录或文件
如果宿主机目录不存在,docker会自动创建这个目录。但是docker只自动创建文件夹,不会创建文件。
例如,mysql的配置文件和数据存储目录使用主机的目录。可以将配置文件设置为只读(read-only)防止容器更改主机中的文件。
1 | docker run -e MYSQL_ROOT_PASSWORD=123456 \ |
2、–tmpfs临时挂载
临时挂载将数据保留在主机内存中,当容器停止时,文件将被删除。
1 | docker run -d -it --tmpfs /tmp nginx:1.22-alpine |
5.2、volume卷
卷 是docker 容器存储数据的首选方式,卷有以下优势:
- 卷可以在多个正在运行的容器之间共享数据。仅当显式删除卷时,才会删除卷。
- 当你想要将容器数据存储在外部网络存储上或云提供商上,而不是本地时。
- 卷更容易备份或迁移,当您需要备份、还原数据或将数据从一个 Docker 主机迁移到另一个 Docker 主机时,卷是更好的选择。
1 | docker volume create my-data |
6、部署自己的应用
本例子我们使用docker来部署一个RuoYi应用系统
将源码编译打包成ruoyi-admin.jar文件,放到宿主机/home/app目录下,/home/app/sql目录下是数据库初始化脚本
1、准备工作:创建网络和存储卷
1 | docker volume create ruoyi-data |
2、部署mysql并初始化数据库
1 | docker run -e MYSQL_ROOT_PASSWORD=123456 \ |
3、部署应用
1 | docker run -p 8080:8080 \ |
7、Docker compose容器编排
在实际工作中,部署一个应用可能需要部署多个容器,一个一个部署非常不方便。docker compose可以一键部署和启动多个容器,它使用yaml文件来编排服务。
github和docker hub很多项目都提供了docker-compose.yaml文件,我们可以一键部署项目,非常方便
7.1、compose文件结构
1 | version: '3' # 指定Compose文件的版本 |
7.2、一键部署wordpress
wordpress是一个著名的开源博客系统。
将以下内容保存到本地的docker-compose.yml文件中。
docker compose命令启动时,默认在当前目录下寻找compose.yaml或compose.yml,
为了兼容之前的版本,也会查找docker-compose.yaml或docker-compose.yml。
也可以使用-f参数手动指定文件docker compose -f docker-compose-dev.yml up -d
1 | services: |
相关命令:
1 | 一键部署启动 |
8、Dockerfile镜像制作
dockerfile通常包含以下几个常用命令:
1 | FROM ubuntu:18.04 |
FROM
打包使用的基础镜像WORKDIR
相当于cd
命令,进入工作目录COPY
将宿主机的文件复制到容器内RUN
打包时执行的命令,相当于打包过程中在容器中执行shell脚本,通常用来安装应用程序所需要的依赖、设置权限、初始化配置文件等CMD
运行镜像时执行的命令EXPOSE
指定容器在运行时监听的网络端口,它并不会公开端口,仅起到声明的作用,公开端口需要容器运行时使用-p参数指定。
8.1、制作自己的镜像
1 | FROM openjdk:8u342-jre |
docker build . 打包
8.2、image镜像与layer层
image文件由一系列层构建而成,dockerfile每一个命令都会生成一个层,每一层都是只读的
可以使用:docker image history + 镜像名 命令查看
创建容器时,会创建一个新的可写层,通常称为“容器层”,对正在运行的容器所做的所有更改(如写入新文件,修改现有文件或删除文件)都将写入容器层而不会修改镜像
8.3、多阶段构建
在构建基于java应用时,需要一个JDK将源码编译为java字节码,但是在生产环境中不需要该JDK。多阶段构建可以将生成时依赖和运行时依赖分开,减少整个image文件大小
以maven/tomcat为例。使用 Maven来构建应用,在最终的image中不需要包含maven。我们可以使用多阶段构建,每一个阶段从FROM
开始,最终的image只会从最后一个阶段构建,不会包含前面阶段产生的层,因此可以减少镜像体积
1 | FROM maven AS build |
ENTRYPOINT和CMD的区别:
dockerfile至少应包含一个ENTRYPONIT和CMD
ENTRYPOINT指定容器启动时执行的默认程序,一般运行容器时不会被替换或覆盖,除非使用–entrypoint进行指定
cmd可以在容器启动时被替换或覆盖
9、私有仓库
我们可以使用docker push将自己的image推送到docker hub中进行共享,但是在实际工作中,很多公司的代码不能上传到公开的仓库中,因此我们可以创建自己的镜像仓库。
docker 官网提供了一个docker registry的私有仓库项目,可以方便的通过docker部署。
1 | docker run -d -p 5000:5000 --restart always --name registry registry:2 |
10、镜像导入导出
当我们处于离线状态,比如在很多内网上不能访问互联网,这时候不能通过镜像仓库的方式共享image,我们可以使用导出和导入功能,手动拷贝镜像
1 | docker save会包含所有层,以及所有标签 + 版本信息 |
注意:
不要跟export和import命令混淆
docker save/load IMAGE save和load操作的是镜像
docker export/import CONTAINER export和import操作对象是容器
image包含多个层,每一层都不可变,save保存的信息包含每个层和所有标签 + 版本信息。
容器运行的时候会创建一个可写入的容器层,所有的更改都写入容器层,export导出的只有容器层,不包含父层和标签信息。