1 常见命令
Docker最常见的命令就是操作镜像、容器的命令,详见官方文档: Docker Docs
视图:
命令:
命令 | 说明 | 文档地址 |
---|---|---|
docker pull | 拉取镜像 | docker pull |
docker push | 推送镜像到DockerRegistry | docker push |
docker images | 查看本地镜像 | docker images |
docker rmi | 删除本地镜像 | docker rmi |
docker run | 创建并运行容器(不能重复创建) | docker run |
docker stop | 停止指定容器 | docker stop |
docker start | 启动指定容器 | docker start |
docker restart | 重新启动容器 | docker restart |
docker rm | 删除指定容器 | docker rm |
docker ps | 查看容器 | docker ps |
docker logs | 查看容器运行日志 | docker logs |
docker exec | 进入容器 | docker exec |
docker save | 保存镜像到本地压缩文件 | docker save |
docker load | 加载本地压缩文件到镜像 | docker load |
docker inspect | 查看容器详细信息 | docker inspect |
docker exec -it 容器名称 bash | 进入容器内部 |
默认情况下,每次重启虚拟机都需要手动启动Docker和Docker中的容器,以下命令可以实现开机自启:
# Docker开机自启
systemctl enable docker
# Docker容器开机自启
docker update --restart=always [容器名/容器id]
2 数据卷
容器是隔离环境,容器内程序的文件、配置、运行时产生的数据都在容器内部,与容器绑定。在某些情况下会带来一些问题,例如:
-
容器被销毁,它的数据也会被一起销毁;
-
容器运行后,其中的某些配置无法被修改;
-
Nginx容器无法代理容器外的静态资源;
因此,容器提供程序的运行环境,但是 程序运行产生的数据、程序运行依赖的配置等都应该与容器解耦。
2.1 概述
-
数据卷(volume)是一个虚拟目录,它将宿主机目录映射到容器内目录;
-
在创建容器时,利用 -v 数据卷名(或本地目录名):容器内目录 完成挂载,本地目录必须以路径开头;
2.2 常见命令
命令 | 说明 | 文档地址 |
---|---|---|
docker volume create | 创建数据卷 | docker volume create |
docker volume ls | 查看所有数据卷 | docker volume ls |
docker volume rm | 删除指定数据卷 | docker volume rm |
docker volume inspect | 查看某个数据卷的详情 | docker volume inspect |
docker volume prune | 清除数据卷 | docker volume prune |
2.3 挂载数据卷
以Nginx为例,Nginx中有两个关键的目录:
-
html
:放置一些静态资源 -
conf
:放置配置文件
如果我们要让Nginx代理我们的静态资源,最好是将资源放到html
目录;
如果我们要修改Nginx的配置,最好是找到conf
下的nginx.conf
文件;
但遗憾的是,容器运行的Nginx所有的文件都在容器内部,读写都非常不方便。所以我们通常会利用数据卷将这两个目录与宿主机目录关联起来,方便我们操作。
视图:
操作:
# 1.创建容器并指定数据卷,注意通过 -v 参数来指定数据卷
docker run -d \
--name nginx \
-p 80:80 \
-v html:/usr/share/nginx/html \ # 数据卷名(或本地目录名): 容器内目录
nginx
# 2.查看数据卷
docker volume ls
# 结果
DRIVER VOLUME NAME
local 29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f
local html
# 3.查看数据卷详情
docker volume inspect html
# 结果
[
{
"CreatedAt": "2023-09-17T19:57:08+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/html/_data",
"Name": "html",
"Options": null,
"Scope": "local"
}
]
# 4.查看/var/lib/docker/volumes/html/_data目录
ll /var/lib/docker/volumes/html/_data
# 可以看到与nginx的html目录内容一样,结果如下:
总用量 8
-rw-r--r--. 1 root root 497 12月 28 2022 50x.html
-rw-r--r--. 1 root root 615 12月 28 2022 index.html
# 5.进入该目录,随意修改index.html内容
cd /var/lib/docker/volumes/html/_data
vi index.html
# 6.打开页面,查看效果
# 7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化
docker exec -it nginx bash
2.4 挂载本地目录
-
在执行docker run命令时,使用 -v 本地目录 : 容器内目录 可以完成本地目录挂载;
-
本地目录必须以 “/” 或 “./” 开头,如果直接以名字开头,会被识别为数据卷而非本地目录;
-
-v mysql : /var/lib/mysql 会被识别为一个叫mysql,运行时会自动创建这个数据卷
-
-v ./mysql : /var/lib/mysql 会被识别为当前目录下的mysql目录,如果不存在会自动创建
-
mysql容器挂载本地目录示例:
# 创建并运行新mysql容器,挂载本地目录
docker run -d \
--privileged=true \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123456 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/log:/var/log/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
mysql:latest
# 查看root/mysql目录
cd root/mysql/
ll
# 结果:
总用量 4
drwxr-xr-x. 2 root root 6 9月 23 12:12 conf
drwxr-xr-x. 6 polkitd root 4096 9月 23 12:34 data
drwxr-xr-x. 2 root root 6 9月 23 12:12 init
drwxr-xr-x. 2 root root 6 9月 23 12:34 log
# 查看data目录,发现里面有大量数据库数据,说明数据库完成了初始化
ls -l data
# 结果:
总用量 198056
-rw-r-----. 1 polkitd input 56 9月 23 12:34 auto.cnf
-rw-r-----. 1 polkitd input 3116921 9月 23 12:34 binlog.000001
-rw-r-----. 1 polkitd input 156 9月 23 12:34 binlog.000002
-rw-r-----. 1 polkitd input 32 9月 23 12:34 binlog.index
-rw-------. 1 polkitd input 1680 9月 23 12:34 ca-key.pem
-rw-r--r--. 1 polkitd input 1112 9月 23 12:34 ca.pem
-rw-r--r--. 1 polkitd input 1112 9月 23 12:34 client-cert.pem
-rw-------. 1 polkitd input 1676 9月 23 12:34 client-key.pem
-rw-r-----. 1 polkitd input 196608 9月 23 12:37 #ib_16384_0.dblwr
-rw-r-----. 1 polkitd input 8585216 9月 23 12:34 #ib_16384_1.dblwr
-rw-r-----. 1 polkitd input 5678 9月 23 12:34 ib_buffer_pool
-rw-r-----. 1 polkitd input 12582912 9月 23 12:35 ibdata1
-rw-r-----. 1 polkitd input 50331648 9月 23 12:37 ib_logfile0
-rw-r-----. 1 polkitd input 50331648 9月 23 12:34 ib_logfile1
-rw-r-----. 1 polkitd input 12582912 9月 23 12:35 ibtmp1
drwxr-x---. 2 polkitd input 187 9月 23 12:34 #innodb_temp
drwxr-x---. 2 polkitd input 143 9月 23 12:34 mysql
-rw-r-----. 1 polkitd input 31457280 9月 23 12:35 mysql.ibd
drwxr-x---. 2 polkitd input 8192 9月 23 12:34 performance_schema
-rw-------. 1 polkitd input 1676 9月 23 12:34 private_key.pem
-rw-r--r--. 1 polkitd input 452 9月 23 12:34 public_key.pem
-rw-r--r--. 1 polkitd input 1112 9月 23 12:34 server-cert.pem
-rw-------. 1 polkitd input 1680 9月 23 12:34 server-key.pem
drwxr-x---. 2 polkitd input 28 9月 23 12:34 sys
-rw-r-----. 1 polkitd input 16777216 9月 23 12:37 undo_001
-rw-r-----. 1 polkitd input 16777216 9月 23 12:37 undo_002
# 通过以下命令可以登录mysql容器
docker exec -it mysql mysql -uroot -p123456
nginx容器挂载本地目录示例:
docker run -d \
--name nginx \
-p 18080:18080 \
-p 18081:18081 \
-v /root/nginx/html:/etc/nginx/html \
-v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
--network hmall \
nginx
3 自定义镜像
-
DK
-
上传Jar包
-
运行jar包
构建Java镜像步骤:
-
准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)
-
安装并配置JDK
-
拷贝jar包
-
配置启动脚本
3.2 镜像结构
-
入口(Entrypoint):镜像运行入口,一般是程序启动的脚本和参数;
-
层(Layer):在BaseImage基础上添加安装包、依赖、配置等,每次操作都形成新的一层;
-
基础镜像(BaseImage):应用依赖的系统函数库、环境、配置、文件等;
3.3 Dockerfile
Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile帮我们构建镜像。常见指定如下:
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM centos:6 |
ENV | 设置环境变量,可在后面指令使用 | ENV key value |
COPY | 拷贝本地文件到镜像的指定目录 | COPY ./xx.jar /tmp/app.jar |
RUN | 执行Linux的shell命令,一般是安装过程的命令 | RUN yum install gcc |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
更多语法可以参考官方文档: Dockerfile reference | Docker Docs
基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下:
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装JDK
RUN cd $JAVA_DIR \
&& tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]
JDK基础镜像:
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
3.4 构建镜像
当Dockerfile文件写好以后,就可以利用命令来构建镜像。
构建镜像命令:
docker build -t docker-demo:1.0 .
-
docker build
: 就是构建一个docker镜像; -
-t docker-demo:1.0
:-t
参数是指定镜像的名称(repository
和tag
),不指定tag时,默认为latest; -
.
: 最后的点是指构建时Dockerfile所在路径,.
代表当前目录,也可以直接指定目录;
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo
4 网络
-
容器的网络IP是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP
发生变化,连接会失败。因此,可以借助于docker的网络功能来解决这个问题;
-
docker的网络功能无需记住IP地址也可以实现容器互联;
-
默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥上;
官方文档:docker network
常见命令有:
命令 | 说明 | 文档地址 |
---|---|---|
docker network create | 创建一个网络 | docker network create |
docker network ls | 查看所有网络 | docker network ls |
docker network rm | 删除指定网络 | docker network rm |
docker network prune | 清除未使用的网络 | docker network prune |
docker network connect | 使指定容器连接加入某网络 | docker network connect |
docker network disconnect | 使指定容器连接离开某网络 | docker network disconnect |
docker network inspect | 查看网络详细信息 | docker network inspect |
自定义网络:
# 1.首先通过命令创建一个网络
docker network create hmall
# 2.然后查看网络
docker network ls
# 结果:
NETWORK ID NAME DRIVER SCOPE
639bc44d0a87 bridge bridge local
403f16ec62a2 hmall bridge local
0dc0f72a0fbb host host local
cd8d3e8df47b none null local
# 其中,除了hmall以外,其它都是默认的网络
# 3.让dd和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
# 这样该网络内的其它容器可以用别名互相访问!
# 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
docker network connect hmall mysql --alias db
# 3.2.db容器,也就是我们的java项目
docker network connect hmall dd
# 4.进入dd容器,尝试利用别名访问db
# 4.1.进入容器
docker exec -it dd bash
# 4.2.用db别名访问
ping db
# 结果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms
# 4.3.用容器名访问
ping mysql
# 结果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms
5 DockerCompose
5.1 概述
Docker Compose指通过一个单独的docker-compose.yml模板文件来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署;
-
项目(project):由一组关联的应用容器组成的一个完整业务单元,在
docker-compose.yml
文件中定义; -
服务(service):一个应用的容器,定义某个应用的运行时参数,实际上可以包括若干运行相同镜像的容器实例;
service
与 docker run
的参数类似。
举例来说,用docker run部署MySQL的命令如下:
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ./mysql/data:/var/lib/mysql \
-v ./mysql/conf:/etc/mysql/conf.d \
-v ./mysql/init:/docker-entrypoint-initdb.d \
--network work01
mysql
如果用docker-compose.yml
文件来定义,就是这样:
docker-compose.yml文件的基本语法参考文档:Compose file version 3 reference
version: "3.8"
services:
mysql:
image: mysql # 镜像名称
container_name: mysql # 容器名称
ports: # 端口映射
- "3306:3306"
environment: # 环境变量
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123
volumes: # 数据卷
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks: # 网络
- new
hmall:
build:
context: .
dockerfile: Dockerfile
container_name: hmall
ports:
- "8080:8080"
networks:
- new
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "18080:18080"
- "18081:18081"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/etc/nginx/html"
depends_on:
- hmall
networks:
- new
networks:
new:
name: work01
对比如下:
docker run 参数 | docker compose 指令 | 说明 |
---|---|---|
--name | container_name | 容器名称 |
-p | ports | 端口映射 |
-e | environment | 环境变量 |
-v | volumes | 数据卷配置 |
--network | networks | 网络 |
5.2 基础命令
docker-compose.yml编辑好之后,需要部署docker-compose.yml文件项目,常见的命令如下:
基本语法:docker compose [OPTIONS] [COMMAND]
其中,OPTIONS和COMMAND都是可选参数,比较常见的有:
类型 | 参数或指令 | 说明 |
---|---|---|
Options | -f | 指定compose文件的路径和名称 |
-p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
Commands | up | 创建并启动所有service容器 |
down | 停止并移除所有容器、网络 | |
ps | 列出所有启动的容器 | |
logs | 查看指定容器的日志 | |
stop | 停止容器 | |
start | 启动容器 | |
restart | 重启容器 | |
top | 查看运行的进程 | |
exec | 在指定的运行中容器中执行命令 |
示例:
# 1.进入root目录
cd /root
# 2.删除旧容器
docker rm -f $(docker ps -qa)
# 3.删除hmall镜像
docker rmi hmall
# 4.清空MySQL数据
rm -rf mysql/data
# 5.启动所有, -d 参数是后台启动
docker compose up -d
# 结果:
[+] Building 15.5s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 358B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 15.4s
=> [1/3] FROM docker.io/library/openjdk:11.0-jre-buster@sha256:3546a17e6fb4ff4fa681c3 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 98B 0.0s
=> CACHED [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 0.0s
=> CACHED [3/3] COPY hm-service.jar /app.jar 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:32eebee16acde22550232f2eb80c69d2ce813ed099640e4cfed2193f71 0.0s
=> => naming to docker.io/library/root-hmall 0.0s
[+] Running 4/4
✔ Network hmall Created 0.2s
✔ Container mysql Started 0.5s
✔ Container hmall Started 0.9s
✔ Container nginx Started 1.5s
# 6.查看镜像
docker compose images
# 结果
CONTAINER REPOSITORY TAG IMAGE ID SIZE
hmall root-hmall latest 32eebee16acd 362MB
mysql mysql latest 3218b38490ce 516MB
nginx nginx latest 605c77e624dd 141MB
# 7.查看容器
docker compose ps
# 结果
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
hmall root-hmall "java -jar /app.jar" hmall 54 seconds ago Up 52 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
mysql mysql "docker-entrypoint.s…" mysql 54 seconds ago Up 53 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
nginx nginx "/docker-entrypoint.…" nginx 54 seconds ago Up 52 seconds 80/tcp, 0.0.0.0:18080-18081->18080-18081/tcp, :::18080-18081->18080-18081/tcp