一、Docker基础
DOcker最常见的命令就是操作镜像
、容器
的命令,详见官方文档:https://docs.docker.com/
tip
:使用 docker xx --help
命令查看docker xx命令的语法
容器生命周期
容器三个状态
- 运行:进程正常运行
- 暂停:进程暂停,CPU不再运行,不释放内存
- 停止:进程终止,回收进程占用的内存、CPU等资源。
常见命令
操作对象 | 命令 | 作用 | 例子 |
---|---|---|---|
镜像 | docker images | 查看本地所有镜像 | - |
- | docker rmi 镜像名:版本 | 删除镜像 | docker rmi mysql:8.0 |
- | docker save -o 文件名 镜像名 | 把镜像存为压缩包 | docker save -o nginx.tar nginx:latest |
- | docker load -i 文件名 | 从压缩包恢复镜像 | docker load -i nginx.tar |
容器 | docker ps -a | 查看所有容器(添加-a参可展示所有容器(包括挂掉的容器)) | - |
- | docker run xx | 运行一个容器 | - |
- | docker pause xx | 让一个运行的容器暂停 | |
- | docker unpause xx | 让一个容器从暂停的状态恢复运行 | |
- | docker stop xx | 停止一个运行的容器 | - |
- | docker logs -f 容器名 | 实时查看容器日志 | docker logs -f mysql |
- | docker exec -it 容器名 bash | 进入容器内部 | docker exec -it nginx bash |
- | docker rm -f 容器名 | 强制删除容器(无论是否运行,添加 -f 参数可以强制删除) | docker rm -f nginx |
常见容器命令演示
- docker run:创建并运行一个容器,处于运行状态
- docker pause xx:让一个运行的容器暂停
- docker unpause xx:让一个容器从暂停的状态恢复运行
- docker stop xx:停止一个运行的容器
- docker start xx:让一个停止的容器再次运行
- docker rm xx:删除一个容器(不能删除正在运行中的容器),添加 -f 参数可以强制删除
- docker logs xx容器名 查看容器日志命令,添加 -f 参数可以持续查看日志
- docker ps 查看运行中的容器,添加-a参可展示所有容器(包括挂掉的容器)。加上–format参数可以用指定格式查看
案例:进入nginx容器,修改 html 文件,添加 Welcome to My Blog!
1. 进入nginx容器
docker exec -it nginx bash
- -it:给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
- nginx:要进入的容器的名称
- bash:进入容器后执行的命令,bash是一个Linux终端交互命令
2. 进入nginx的html所在的目录
查看DockerHub网站中nginx页面,可以知道nginx的html位置在 /usr/share/nginx/html
## 进入目录
cd /usr/share/nginx/html
## 查看文件
ls
>> 50x.html index.html
## 修改文件,容器内没有vi命令,无法直接修改,会报错
vi index.html
>> error. command not found
## 可使用以下命令进行修改(但不推荐)
sed -i -e 's#Welcome to nginx#Welcome To My Blog#g' index.html
访问 虚拟机ip:80(80端口可以不写),即可看到结果
Q:目前存在的问题,数据与容器耦合度较高
- 容器没有提供vi命令,
不能直接编辑
,修改起来需要进入容器内部比较麻烦。 - 在容器内的修改对外是不可见的,所有修改对新创建的容器是不可复用的
- 升级维护困难:数据在容器内,如果要升级容器必然
删除旧容器,所有数据也删除掉
了。这是因为容器内的数据默认是临时的,想让数据永久保存,就得用数据卷。
二、数据卷
什么是数据卷?
数据卷是一个虚拟目录
,它将宿主机目录映射到容器内目录,方便我们操作容器内文件,或者方便迁移容器产生的数据。
简单说,数据卷是宿主机和容器之间的共享文件夹:
- 你在宿主机的这个文件夹里操作,容器内对应的目录会同步变化;
- 就算容器删了,宿主机的文件还在,重新挂载后数据能恢复。
如何挂载数据卷?
在执行docker run
命令创建容器时,利用-v 数据卷名:容器内目录
完成挂载。容器创建时,如果发现挂载的数据卷不存在时,会自动创建。
一旦完成数据卷挂载,对容器的一切操作都会对应作用在宿主机目录了,这样操作宿主机的**/var/lib/docker/volumes/html目录就相当于操作容器内的/usr/share/nginx/html**目录。
docker volumn --help
查看具体有哪些命令
数据卷的常见命令有哪些?
- docker volume create app-data: 创建一个volume:app-data
- docker volume ls: 查看数据卷
- docker volume rm app-data: 删除数据卷
- docker volume inspect app-data: 查看数据卷详情
- docker volume prune: 删除未使用的数据卷
- docker run -v app-data:/app nginx 挂载数据卷
案例1:利用Nginx容器部署静态资源
需求:创建Nginx容器,修改nginx容器内的html目录下的 index.html 文件内容,将静态资源部署到nginx的html目录
# 数据卷html挂载到容器内的html目录
docker run --name nginx -v html:/usr/share/nginx/html -p 80:80 -d nginx
# 查看数据卷位置 找到"Mountpoint"字段,比如/var/lib/docker/volumes/html/_data
docker volume inspect html
# 进入该目录
cd /var/lib/docker/volumes/html/_data
# 修改文件
vi index.html
案例2:mysql容器的数据挂载
容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上
- 带数据卷模式:宿主机目录 --> 数据卷 —>容器内目录
- 直接挂载模式:宿主机目录 --> 容器内目录
数据卷挂载 VS 目录直接挂载
方式 | 优点 | 缺点 | 适合场景 |
---|---|---|---|
数据卷挂载 | 耦合度低,Docker 自动管理,路径安全 | 宿主机路径深,不好找 | 长期使用的服务 |
宿主机目录挂载 | 路径直观,方便手动操作 | 耦合度高,需自己管理目录权限 | 开发环境、临时测试 |
需求: 基于宿主机目录实现MySQL数据目录、配置文件、初始化脚本的挂载(查阅官方镜像文档)
提示:在执行docker run命令时,使用-v 本地目录:容器内目录 可以完成本地目录挂载
本地目录必须以"/" 或"./"开头,如果直接以名称
开头,会被识别为数据卷
而非本地目录
- -V mysql:/var/ib/mysql 会被识别为一个数据卷叫mysq|
- -V ./mysql:/var/lib/mysql 会被识别为当前目录下的mysqI目录
查阅资料可知,mysql容器内conf目录位置是 /etc/mysql/conf.d
;容器内存储数据的目录是:/var/lib/mysql
docker pull mysql
# 在宿主机创建文件夹
mkdir -p /tmp/mysql/data /tmp/mysql/conf
# 启动MySQL时挂载这两个目录
docker run -d --name mysql \
-p 3307:3306 \
-e TZ=Asia/shanghai \
-e MYSQL_ROOT_PASSWORD=root \
-v /tmp/mysql/data:/var/lib/mysql \
-v /tmp/mysql/conf:/etc/mysql/conf.d \
mysql
三、自定义镜像:把你的应用打包成“安装包”
如果想让自己写的程序(比如 Java、Python 应用)也能一键运行,就需要把它打包成 Docker 镜像。
镜像的结构是怎样的?
镜像中包含了应用程序所需要的运行环境、函数库、配置
、以及应用本身
等各种文件,这些文件分层打包而成。
Dockerfile是做什么的?
Dockerfile是一个文本文件,利用简单固定的指令描述镜像的结构和构建过程,这样Docker才可以依次来构建镜像
构建镜像的命令是什么?
docker build -t 镜像名 Dockerfile目录
Dockerfile核心指令
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM openjdk:11 |
ENV | 设置环境变量 | ENV key value |
COPY | 复制文件,拷贝本地文件到镜像的指定目录 | COPY ./jre11.tar.gz /tmp |
RUN | 执行Linux的shell命令,一般是 安装过程的命令 | RUN apt-get update |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
我们可以基于Ubuntu基础镜像,利用Dockerfile描述镜像结构, 也可以直接基于JDK为基础镜像,省略前面的步骤:
案例:基于Java8构建Java项目
1. 准备工作
- 把你的 Java 项目打包成
app.jar
,放在/tmp/myapp
目录下; - 在同一目录创建Dockerfile(文件名固定)。
2. 编写 Dockerfile
# 1. 基于Java8环境(相当于“操作系统+Java”)
FROM openjdk:8
# 2. 把宿主机的app.jar拷贝到容器里
COPY ./app.jar /tmp/app.jar
# 3. 声明应用运行的端口
EXPOSE 8080
# 4. 容器启动时执行的命令(启动Java程序)
ENTRYPOINT ["java", "-jar", "/tmp/app.jar"]
3. 构建并运行镜像
# 进入Dockerfile所在目录,构建镜像
docker build -t myapp:1.0 . # 镜像名:版本 点表示当前目录
# 启动容器
docker run -d \
--name myapp \
-p 8080:8080 \
myapp:1.0
访问宿主机IP:8080,就能看到你的应用了。
tip:
- Dockerfile的第一行必须是FROM,从一个基础镜像来构建
- 基础镜像可以是基本操作系统,如Ubunut,也可以是其他人制作好的镜像,例如openjdk:8、java:8-alpine
四、容器网络:互联互通
默认网络模型:
网络常见命令
命令 | 说明 |
---|---|
docker network create | 创建一个网络 |
docker network ls | 查看所有网络 |
docker network rm | 删除指定网络 |
docker network prune | 清除未使用的网络 |
docker network connect | 使指定容器连接加入某网络 |
docker network di sconnect | 使指定容器连接离开某网络 |
docker network inspect | 查看网络详细信息 |
自定义网络示例
# 创建网络
docker network create app-net
# 容器加入网络
docker run -d --name mysql --network app-net mysql
docker run -d --name app --network app-net my-app:1.0
网络优势
- 容器间通过名称直接访问
- 网络隔离更安全
- 避免端口冲突
DockerCompose:一键启动多个关联容器
实际项目中,一个应用往往需要多个服务(比如 Java 后端 + MySQL+Redis)。手动一个个启动太麻烦,用Docker Compose可以一键搞定。
docker compose的命令格式如下:
docker compose [OPTIONS] [COMMAND]
类型 | 参数或指令 | 说明 |
---|---|---|
Options | -f | 指定compose文件的路径和名称 |
- | -p | 指定project名称 |
Commands | up | 创建并启动所有service容器 |
- | down | 停止并移除所有容器、网络 |
- | ps | 列出所有启动的容器 |
- | logs | 查看指定容器的日志 |
- | stop | 停止容器 |
- | start | 启动容器 |
- | restart | 重启容器 |
- | top | 查看运行的进程 |
- | exec | 在指定的运行中容器中执行命令 |
核心用法:写个docker-compose.yml
配置文件
示例:启动 Java 应用 + MySQL
创建docker-compose.yml
:
version: "3.8" # 固定格式
services:
# MySQL服务
mysql:
image: mysql:8.0 # 用官方MySQL镜像
environment:
MYSQL_ROOT_PASSWORD: 123456 # 数据库密码
volumes:
- /tmp/mysql/data:/var/lib/mysql # 挂载数据目录
# 你的Java应用服务
myapp:
build: ./myapp # 从./myapp目录的Dockerfile构建镜像
ports:
- "8080:8080" # 端口映射
depends_on:
- mysql # 先启动MySQL再启动应用
environment:
# 连接MySQL时,用服务名“mysql”当主机名(Docker内部自动解析)
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydb
启动和停止命令
# 启动所有服务(在yml文件所在目录)
docker compose up -d # -d表示后台运行
# 停止并删除所有服务(数据不会丢,因为挂载了卷)
docker compose down
docker compose ps # 查看服务状态
docker compose logs # 查看日志
上述的Compose文件描述一个项目,其中包含两个容器:
- mysql:基于mysql:5.7.25 镜像构建的容器,并且挂载了两个项目
- web: 基于docker:build 临时构建的镜像容器,映射端口为8090
利用DockerCompose部署微服务集群
- 准备dockercompose文件
- 修改项目配置,将数据库、nacos地址都命名为docker-compose中的服务名
- 使用maven打包工具,将项目中的每个微服务都打包为app.jar
- 将cloud-demo上传至虚拟机,利用
docker-compose up -d
来部署
五、镜像仓库:存镜像的 “云盘”
镜像仓库就像 “应用商店”,用来存放你构建的镜像,方便在不同机器上使用。
1. 公共仓库(直接用)
- Docker Hub:官方仓库,有各种现成镜像(如mysql、nginx);
- 阿里云镜像仓库:国内访问快,可搜 “阿里云镜像服务” 获取加速地址。
2. 推送自己的镜像到仓库(可选)
如果想分享自己的镜像,步骤如下:
# 1. 给镜像打标签(仓库地址/镜像名:版本)
docker tag myapp:1.0 你的仓库地址/myapp:1.0
# 2. 推送镜像
docker push 你的仓库地址/myapp:1.0
# 3. 在其他机器拉取
docker pull 你的仓库地址/myapp:1.0
常见问题解决
1. 容器无法访问外部网络
# 检查DNS配置
docker run --rm busybox nslookup google.com
# 解决方案:自定义DNS
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"dns": ["8.8.8.8", "114.114.114.114"]
}
EOF
2. 端口冲突处理
# 查找占用端口进程
sudo lsof -i :8080
# 解决方案:
# 1. 停止冲突进程
# 2. 修改容器映射端口:-p 8081:8080
3. 存储空间清理
# 删除所有停止的容器
docker container prune
# 删除未使用的镜像
docker image prune -a
# 删除未使用的数据卷
docker volume prune
总结:这篇的核心知识点
- 命令:掌握镜像和容器的增删查改,docker exec进入容器;
- 数据卷:用-v挂载数据,避免容器删除导致数据丢失;
- 自定义镜像:用 Dockerfile 打包自己的应用,实现 “一次构建,到处运行”;
- Docker Compose:通过docker-compose.yml管理多个服务,一键启动集群。