Docker简介
- 定义:Docker是一个开源的应用容器引擎
- 优势:
- 一键部署,开箱即用:容器使用基于image镜像的部署模式,image中包含运行应用程序所需的一切:代码、运行时系统工具、系统库和配置文件
- 一次打包,到处运行:将容器打包成镜像(image)已经成为软件交付过程中的标准化格式
- 容器与虚拟机:
Linux下安装Docker
其中涉及
- docker-ce:服务端
- docker-ce-cli:客户端
- containerd.io:容器运行时
- docker-compose-plugin: 容器编排的工具
客户端发出指令发送给服务端对容器操作,服务端并不直接操作,而是交给containerd创建容器
配置国内镜像源加速
在/etc/docker/daemon.json
中添加
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
然后重启服务和docker
sudo systemctl daemon-reload
sudo systemctl restart docker
Docker常用命令
docker架构
Registry:Docker 镜像仓库地址:地址的格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub(docker.io
)仓库名:
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。镜像名:
软件名+标签
命令 | 解释 |
---|---|
docker pull | 从镜像仓库拉取镜像到本地 |
docker images | 命令查看本地镜像 |
docker run [可选参数] 镜像名:版本 [] | 拉取并运行镜像 可选参数:1. 参数将容器的端口映射到宿主机端口 -p hostPort:containerPort -p 8080-8090:8080-8090 公开端口范围,前后必须对应-p 192.168.56.106:8080:80 如果宿主机有多个ip ,可以指定绑定到哪个ip 2. --name 定义容器的名称3. -e 声明环境变量4. -d 容器在后台运行5. -it 使用交互模式,可以在控制台里输入、输出6. --rm **在容器退出时自动删除容器。**一般在使用客户端程序时使用此参数 |
docker start 容器名 | 启动容器 |
docker stop | 关闭容器 |
docker restart | 重启容器 |
docker rm | 删除容器 |
docker exec | 在运行的容器中执行命令,一般配合-it 参数使用交互模式 |
docker ps | 查看正在运行的容器 |
docker ps -a | 查看所有容器,包括正在运行和停止的 |
docker inspect | 查看容器的信息 |
docker logs | 查看日志 |
docker cp | 在容器和宿主机间复制文件 |
Docker网络
docker自动创建的三个网络
-
bridge桥接网络:
如果不指定,新创建的容器默认将连接到bridge网络。容器和宿主机,容器和容器可以相互访问。
-
host:
容器与宿主机共享网络,不需要映射端口即可通过宿主机IP访问。(-p选项会被忽略),慎用,可能会有安全问题。
-
none:
禁用容器中所用网络,在启动容器时使用。
-
用户自定义网络(桥接网络)
-
创建用户自定义网络
docker network create my-net
-
将已有容器连接到此网络
docker network connect my-net db-mysql
-
创建容器时指定网络。
docker run -it --rm --network my-net mysql:5.7 mysql -h**db-mysql** -uroot -p
在用户自定义网络上,容器之间可以通过容器名进行访问。
用户自定义网络使用 Docker 的嵌入式
DNS
服务器将容器名解析成IP
。 -
查看容器IP
docker inspect \ --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-alpine
Docker存储
为了容器的简洁,便于恢复和迁移,需要将数据存储到容器之外,这就是挂载
docker提供的三种存储选项
-
volume卷
卷存储在主机文件系统分配一块专有存储区域,由 Docker(在 Linux 上)管理,并且与主机的核心功能隔离。非 Docker 进程不能修改文件系统的这一部分。卷是在 Docker 中持久保存数据的最佳方式。
创建和挂载卷
docker volume create my-data docker run -e MYSQL_ROOT_PASSWORD=123456 \ -v /home/mysql/conf.d/my.cnf:/etc/mysql/conf.d/my.cnf:ro \ -v my-data:/var/lib/mysql \ -d mysql:5.7
-
bind mount 绑定挂载
绑定挂载可以将主机文件系统上目录或文件装载到容器中,但是主机上的非 Docker 进程可以修改它们,同时在容器中也可以更改主机文件系统,包括创建、修改或删除文件或目录,使用不当,可能会带来安全隐患。
-v
绑定挂载将主机上的目录或者文件装载到容器中。绑定挂载会覆盖容器中的目录或文件。
如果宿主机目录不存在,docker会自动创建这个目录。但是docker只自动创建文件夹,不会创建文件。
例如,mysql的配置文件和数据存储目录使用主机的目录。可以将配置文件设置为只读(read-only)防止容器更改主机中的文件。
docker run -e MYSQL_ROOT_PASSWORD=123456 \ -v /home/mysql/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro \ -v /home/mysql/data:/var/lib/mysql \ -d mysql:5.7
-
tmpfs 临时挂载
tmpfs挂载仅存储在主机系统的内存中,从不写入主机系统的文件系统。当容器停止时,数据将被删除。docker run -d -it --tmpfs /tmp nginx:1.22-alpine
docker-compose
Docker Compose
是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用。
-
常用命令
命令 解释 docker compose up
一键部署启动
主要参数:
1.-f
参数手动指定文件
2.-p
指定前缀docker compose start/stop
启动/停止服务 docker compose down
停止并删除容器,不会删除存储卷volume
1.-p
指定前缀docker compose logs -f
查看日志 -
yaml
语法- 缩进代表上下级关系
- 缩进时不允许使用Tab键,只允许使用空格
:
键值对,后面必须有空格-
列表,后面必须有空格[ ]
数组#
注释{key:value,k1:v1}
map|
多行文本块
如果一个文件中包含多个文档
-
---
表示一个文档的开始 -
用
&
来建立锚点,<<
合并到当前数据,用*
引用锚点version: '3.7' # Settings and configurations that are common for all containers x-minio-common: &minio-common image: quay.io/minio/minio:RELEASE.2022-08-13T21-54-44Z command: server --console-address ":9001" http://minio{1...2}/data{1...2} expose: - "9000" - "9001" services: minio1: <<: *minio-common volumes: - data1-1:/data1 - data1-2:/data2 minio2: <<: *minio-common volumes: - data2-1:/data1 - data2-2:/data2 volumes: data1-1: data1-2: data2-1: data2-2:
-
compose
文件结构docker-compose.yml
通常需要包含以下几个顶级元素:version
已弃用,早期版本需要此元素。services
必要元素,定义一个或多个容器的运行参数在
services
中可以通过以下元素定义容器的运行参数
image
容器 镜像
ports
端口映射
environment
环境变量
networks
容器使用的网络
volumes
容器挂载的存储卷
command
容器启动时执行的命令
depends_on
定义启动顺序 复数形式(例如
ports
,networks
,volumes
,depends_on
)参数需要传入列表networks
创建自定义网络volumes
创建存储卷command
支持以下写法:#推荐使用数组或列表的方式 #数组 command: ["java", "-jar", "/usr/local/src/ruoyi-admin.jar" ] #列表 command: - java - -jar - /usr/local/src/ruoyi-admin.jar # shell命令模式 command: java -jar /usr/local/src/ruoyi-admin.jar
environment
支持如下两种写法# 使用map environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: '1' #使用列表 environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=ry - LANG=C.UTF-8
-
depends_on、condition和healthcheck
depends_on
只能保证容器的启动和销毁顺序,不能确保依赖的容器是否ready。condition
有三种状态:-
service_started
容器已启动 -
service_healthy
容器处于健康状态 -
service_completed_successfully
容器执行完成且成功退出(退出状态码为0)
通过
healthcheck
加脚本来检查healthcheck: test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD'] interval: 10s timeout: 5s retries: 5 start_period: 10s
-
services: ruoyi-app: # docker run --name ruoyi-app \ # -p 8080:8080 \ # --network ruoyi-net \ # -v /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar \ # -d openjdk:8u342-jre \ # java -jar /usr/local/src/ruoyi-admin.jar image: openjdk:8u342-jre restart: always ports: - 8080:8080 networks: - ruoyi-net volumes: - /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar command: [ "java", "-jar", "/usr/local/src/ruoyi-admin.jar" ] healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080"] interval: 10s timeout: 5s retries: 5 start_period: 10s depends_on: ruoyi-db: condition: service_healthy ruoyi-db: # docker run --name ruoyi-db -p 3303:3306 \ # --network ruoyi-net \ # -v ruoyi-data:/var/lib/mysql \ # -v /home/app/sql:/docker-entrypoint-initdb.d \ # -e MYSQL_DATABASE=ry \ # -e MYSQL_ROOT_PASSWORD=123456 \ # -d mysql:5.7 \ # --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-character-set-client-handshake image: mysql:5.7 environment: - MYSQL_DATABASE=ry - MYSQL_ROOT_PASSWORD=123456 volumes: - ruoyi-data:/var/lib/mysql - /home/app/sql:/docker-entrypoint-initdb.d networks: - ruoyi-net command: [ "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci", "--skip-character-set-client-handshake" ] healthcheck: test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD'] interval: 10s timeout: 5s retries: 5 start_period: 10s volumes: ruoyi-data: networks: ruoyi-net:
-
dockerfile制作镜像
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像。
-
常用命令和指令
命令
命令 解释 docker build [选项] <上下文路径/URL/->
构建镜像,将客户端的路径指定为上下文路径
选项-t
指定镜像名docker tag <id> <镜像名>
修改镜像名 docker image history <镜像名>
查看镜像构建过程 指令
命令 解释 FROM
打包使用的基础镜像 WORKDIR
相当于 cd
命令,进入容器工作目录COPY
将宿主机的文件复制到容器内 RUN
打包时执行的命令,相当于打包过程中在容器中执行shell脚本,通常用来安装应用程序所需要的依赖、设置权限、初始化配置文件等 CMD
指定容器启动程序及参数,会被运行容器时的其他指令替代 EXPOSE
指定容器在运行时监听的网络端口,它并不会公开端口,仅起到声明的作用,公开端口需要容器运行时使用-p参数指定。 ENTRYPOINT
指定容器启动程序及参数,一般运行容器时不会被替换或覆盖,而会追加。
如果镜像中ENTRYPOINT
和CMD
都存在,则CMD
将作为ENTRYPOINT
的参数使用。 -
制作自己的镜像
根据以下配置,制作dockerfile
ruoyi-java: image: openjdk:8u342-jre ports: - 8080:8080 volumes: - /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar command: [ "java", "-jar", "/usr/local/src/ruoyi-admin.jar" ] networks: - ruoyi-net depends_on: - ruoyi-db
编写dockerfile文件
FROM openjdk:8u342-jre WORKDIR /app COPY ./ruoyi-admin.jar . CMD ["java", "-jar", "ruoyi-admin.jar"] EXPOSE 8080
-
image镜像与layer层
image文件由一系列层构建而成,dockerfile每一个命令都会生成一个层。每一层都是只读的。
创建容器时,会创建一个新的可写层,通常称为“容器层”。对正在运行的容器所做的所有更改(如写入新文件、修改现有文件和删除文件)都将写入容器层,而不会修改镜像。
-
多阶段构建
在构建基于 Java 的应用程序时,需要一个 JDK 将源代码编译为 Java 字节码。但是,在生产中不需要该 JDK。
多阶段构建可以将生成时依赖与运行时依赖分开,减小整个image文件大小
还是上面的例子
FROM maven AS build WORKDIR /source COPY . . RUN mvn package FROM openjdk:8u342-jre WORKDIR /app COPY --from=build /source/ruoyi-admin/target/ruoyi-admin.jar . EXPOSE 80 ENTRYPOINT ["java","-jar","ruoyi-admin.jar"]
docker build -t ruoyi-jar:4.7.4 .
# project name name: "app" services: ruoyi-java: image: ruoyi-jar:4.7.4 command: [ "--server.port=8080", "--ruoyi.profile=/home/ruoyi/uploadPath", "--spring.datasource.druid.master.url=jdbc:mysql://ruoyi-db:3306/ry?useUnicode=true&characterEncoding=utf8", "--spring.datasource.druid.master.username=root", "--spring.datasource.druid.master.password=123456" ] ports: - 8080:8080 networks: - ruoyi-net healthcheck: test: [ "CMD", "curl", "-f", "http://localhost:8080" ] interval: 10s timeout: 5s retries: 5 start_period: 10s depends_on: ruoyi-db: condition: service_healthy ruoyi-db: image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=ry command: [ "--character-set-server=utf8mb4", "--collation-server=utf8mb4_general_ci", "--skip-character-set-client-handshake" ] volumes: - /home/app/sql:/docker-entrypoint-initdb.d - ruoyi-data:/var/lib/mysql networks: - ruoyi-net healthcheck: test: [ "CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD' ] interval: 10s timeout: 5s retries: 5 start_period: 10s volumes: ruoyi-data: networks: ruoyi-net:
私有仓库
在实际工作中,很多公司的代码不能上传到公开的仓库中,因此我们可以创建自己的镜像仓库。
docker run -d -p 5000:5000 --restart always --name registry registry:2 # 爬取并运行registry,并把端口映射为5000
docker image tag ruoyi-java:4.7.4 localhost:5000/ruoyi-java:4.7.4 #修改tag添加registry地址
docker push localhost:5000/ruoyi-java:4.7.4 # 推送镜像
docker pull localhost:5000/ruoyi-java:4.7.4 # 拉取镜像
修改/etc/docker/daemon.json
,将私有仓库设置为http
也可以访问,添加一行。
"insecure-registries": ["192.168.56.108:5000"] #这里地址是本机地址
镜像导入导出
命令 | 解释 |
---|---|
docker save | 将一个或多个image打包保存的工具 选项 -o 指定保存文件名 |
docker load | 将保存的镜像文件载入成镜像-i 指定载入的文件名 |
docker export | 将container的文件系统进行打包保存-o 指定保存文件名 |
docker import | 将container 保存文件导入后会成为一个image |
不要跟export和import命令混淆
docker save/load IMAGE
save和load操作的是镜像
docker export/import CONTAINER
export和import操作对象是容器image包含多个层,每一层都不可变,save保存的信息包含每个层和所有标签 + 版本信息。
容器运行的时候会创建一个可写入的容器层,所有的更改都写入容器层,export导出的只有容器层,不包含父层和标签信息。
-
docker save保存的是镜像(image),docker export保存的是容器(container);
-
docker load用来载入镜像包,docker import用来载入容器包,但两者都会恢复为镜像;
-
docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称。
-
若是只想备份image,使用save和load。
-
若是在启动容器后,容器内容有变化,需要备份,则使用export和import。
扩展
postgres-save.tar
:docker save
导出的文件
postgres-export.tar
:docker export
导出的文件
分层的文件系统。Docker镜像实际上就是由这样的一层层文件进行叠加起来的,上层的文件会覆盖下层的同名文件。如果将postgres-save.tar
中的各层文件合并到一起,基本就是postgres-export.tar
的内容。由于postgres-save.tar
里面的各层文件会存在很多重复的文件,这也解释了为什么postgres-save.tar
会比postgres-export.tar
大100多M。
docker load
必须要载入的是一个分层文件系统,而postgres-export.tar
并不具有这样的结构,因此无法载入。
而docker import
仅仅是将tar包里面的文件复制进来,所以不管tar包里面的文件结构是怎样的,都可以载入进来,所以能够载入postgres-save.tar
。但postgres-save.tar
并不是一个有效的操作系统镜像,因此当我试图以改镜像启动容器时,容器并不能启动
参考
- docker一小时入门教程 (yuque.com)
- https://yeasy.gitbook.io/docker_practice/
- https://jingsam.github.io/2017/08/26/docker-save-and-docker-export.html