一文搞定docker基础 | 基于docker compose 的项目部署
本文由作者的学习笔记和经验转化而来,共计13458字,预计阅读时间41分钟;包含了docker基础知识和实战指南
如果只是想用docker快速部署项目,可以直接跳转到"实战-使用Docker compose部署"
整理不易,给我点个赞吧 o( ̄▽ ̄)d
- Docker的作用
- 忽略了安装的复杂过程
- 忽略了系统间的差异
- 忽略了系统和应用之间的干扰
- 大幅提高部署效率
镜像和容器
当我们利用Docker安装应用时,Docker会自动搜索并下载应用镜像。镜像不仅包含应用本身,还包含应用运行所需要的环境、配置、系统函数库。Docker会在运行镜像时创建一个隔离环境,称为容器
镜像仓库:存储和管理镜像的平台(Docker官方维护的镜像仓库是DockerHub)
一个镜像不依赖于操作系统,不仅可以在linux上用,还可以在其他系统上用
【镜像把它所依赖的系统环境及其函数库也一起打包了,所以镜像中的应用可以在各种操作系统直接运行】
各个应用所需的环境、函数库往往都不一样,通过容器这种隔离环境的机制,让各个应用各自运行、相互不干扰
镜像只用下载一次,一个镜像可以多开(可以开启多次)、不需要重复下载
如何获取到镜像?
- 从docker/国内公司 维护的镜像仓库,就能获取到想要的镜像(或者公司也可以搭建自己的镜像仓库的私服(类似maven私服))
DockerHub——该网站作用:方便我们查阅里面已经保存的镜像和版本号】
- docker安装好之后,系统就会启动一个守护进程(用来处理客户端发过来的一些请求[比如docker run ]),监听到请求之后就会从镜像仓库找到这个镜像
- 然后将这个镜像(image)下载到本地
- docker可以基于一个镜像构建出多个容器(多个容器之间相互隔离互不影响),各个容器之中可以独立的运行不同的软件、相互独立互不影响(每个容器有独立的网络环境、ip地址等)
执行指令的时候,docker先会从本地找镜像、本地没有才从镜像仓库下载
容器id:容器的唯一标识
Docker基础
Docker安装
不同系统的安装流程推荐查看官方文档
(centos版本流程如下)
移除系统中的旧版本Docker
textyum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-engine \ docker-selinux配置Docker的yum库
首先安装一个yum工具
textsudo yum install -y yum-utils device-mapper-persistent-data lvm2安装成功后,执行命令,配置Docker的yum源(已更新为阿里云源)
textsudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo更新yum,建立缓存
Bashsudo yum makecache fast安装Docker
执行命令、安装Docker
Bashyum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin启动和校验
text# 启动Docker systemctl start docker # 停止Docker systemctl stop docker # 重启 systemctl restart docker # 设置开机自启动 systemctl enable docker # 执行docker ps命令,如果不报错,说明安装启动成功 docker ps配置镜像加速
镜像地址可能会变更,如果失效可以百度找最新的docker镜像。
配置镜像步骤如下:
text# 创建目录 rm -f /etc/docker/daemon.json # 复制内容 tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "http://hub-mirror.c.163.com", "https://mirrors.tuna.tsinghua.edu.cn", "http://mirrors.sohu.com", "https://ustc-edu-cn.mirror.aliyuncs.com", "https://ccr.ccs.tencentyun.com", "https://docker.m.daocloud.io", "https://docker.awsl9527.cn" ] } EOF # 重新加载配置 systemctl daemon-reload # 重启Docker systemctl restart docker
配置阿里镜像加速

-
具体流程参照官网的操作文档即可
完成流程之后可以用docker run hello-world测试,此时下载镜像就很快了
常见命令
-
拉取镜像, 以nginx为例
text# docker pull 镜像名:版本号 docker pull nginx:1.20.2 -
查看本地镜像列表
textdocker images
删除镜像
textdocker rmi nginx:1.20.2跟名称/id
-
创建并运行容器
textdocker run -d --name nginx -p 80:80 nginx:1.20.2nginx不用环境变量,所以没加-e参数
注意:docker run是创建并运行,每次执行都会创建一个新的容器(注意判断是否有必要使用,可能容器只是stop了,没必要再创建一个)
-
查看容器(查看和容器相关的进程)
textdocker ps默认只查看运行中的容器 推荐加上 -a
查看所有容器
textdocker ps -a -
停止容器
textdocker stop nginx -
再次启动容器
textdocker start nginx -
进入容器
textdocker exec -it nginx bashbash:指通过命令行和容器交互,进入nginx容器之后,会打开一个bash shell命令行进行交互

退出容器
textexit -
删除容器
textdocker stop nginx docker rm nginx注意和docker rm 区分34
如何将镜像打包并发给别人:
textdocker save -o nginx-1.20.2.tar nginx:1.20.2打包之后下载到本地就可以发给别人
textdocker load -i nginx-1.20.2.tar其他方式
把(可能是自己构建的)镜像
使用docker push推到镜像仓库(公用/公司的私服)
-
其他
-
保存镜像
text# docker save -o 保存到的文件名 镜像名:版本 docker save -o nginx.tar nginx:latest -
读取本地的镜像
text# docker load -i 要读取的文件名 docker load -i nginx.tar -
查看容器日志
text# docker logs 镜像名 docker logs nginx -
进入mysql容器里面的mysql
textdocker exec -it mysql mysql -uroot -p
-
不清楚某个指令可以加上 “–help”查看帮助文档
textdocker save --help
docker run 命令解读
-
text
docker run -d \ --name mysql \ -p 3307:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123 \ mysql:8
docker run :创建并运行一个容器,-d是让容器在后台运行
–name musql :给容器起个名字,必须唯一
-p 3307:3306:设置端口映射
-e KEY=VALUE:设置环境变量
端口映射
宿主机的端口:容器的端口
当外部访问宿主机的3307端口的时候,dokcer就会把这个请求转到容器内的3306端口
如果有两台mysql容器,就要映射到宿主机的不同端口(宿主机只有一个3306端口)
不同镜像,需要配置的环境变量不一样、是由官方决定的(需要去官网查询需要/必配置的 环境变量)
在hub.docker.com找到对应的镜像,然后找到他需要配置的环境变量
最后的mysql是镜像的名字,搜索部署和下载都是靠这个名字来指定的
text# 查看指定容器的信息 docker inspect containerName
镜像名称一般由两部分组成:
[repository]:[tag]
即 镜像名:版本号
如果不填版本号,默认最新版
运行容器一条龙
-
在DockerHub中搜索xx镜像,查看镜像名称
-
拉取xx镜像
textgit pull 镜像名:版本号 或 git pull 镜像名 -
查看本地镜像列表(是否拉取成功)
textdocker images -
查看镜像需要的环境变量
-
创建并运行x容器(注意设置容器名、端口映射、配置环境变量)
textdocker -run -d --name 镜像名 -p 宿主机端口:容器端口 -e 环境变量1=xx 容器名 -
查看容器(容器是否创建成功)
textdocker ps -a
技巧
设置 指令别名
-
案例
设置简化输出进程信息的指令
-
进入 ~/.bashrc
textvi ~/.bashrc -
设置别名
textalias dps='docker ps --format "table {{.ID}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" -a' -
让别名生效
textsource ~/.bashrc
数据卷
案例需求:
- 创建Nginx容器,修改nginx容器内的html目录下的index.html文件,查看变化
- 将静态资源部署到nginx的html目录
- 但是所有镜像都是最小化的系统环境,它只具备运行所必须的环境
所以在容器内修改文件、拷贝文件很困难所以需要借助数据卷来操作

-
数据卷是虚拟的,但是宿主机会自动在指定目录下创建对应的和数据卷绑定的目录,数据卷又和容器有关联;从而让容器和宿主机映射
双向绑定,一边变 另一边也变
-
指令一览
- docker volume create 创建数据卷
- docker volume ls 查看所有数据卷
- docker volume rm 数据卷名 ——删除指定数据卷
- docker volume inspect 数据卷名 ——查看某个数据卷的详情
- docker volume prune ——清楚所有未使用的数据卷
textdocker volume --help
创建容器的同时才能挂载数据卷,如果容器已经创建了 ,就没办法挂载数据卷了
在执行docker run 命令时,使用-v 数据卷:容器内目录 形式,就可以完成数据卷挂载
具体挂载的容器内目录去官网看
-
案例需求解决
textdocker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx这里的html是数据卷名字,冒号后是容器内目录
- 通过docker volume ls可以查看已经挂载的数据卷
指令-展示数据卷的详细信息
docker volume inspect 数据卷名字
包括映射到的文件位置

本地目录挂载(自定义挂载位置)
匿名数据卷:
起到数据备份的作用
容器自带;
缺点:名字长;挂载位置深;不方便迁移建议挂载到固定的、自己设置的目录
命令
docker run -d --name 容器名 -p 宿主机端口:容器端口 -v 宿主机目录或文件:容器内目录或文件 镜像名
注意
本地目录必须 以 / 或 ./ 开头,如果直接以名称开头,会被识别为数据卷而非本地目录
-v mysql:/var/lib/mysql 会被识别为一个数据卷,数据卷叫mysql
-v ./mysql:/var/lib/mysql 会被识别为当前目录下的mysql目录
案例
本地目录挂载实现 MySQL容器数据目录、配置文件、初始化脚本的目录挂载
textdocker run -d \ --name mysql \ -p 3306:3306 \ -e TZ-Asia/shanghai \ -e MYSQL_ROOT_PASSWORD-123 \ -v /root/mysql/data:/var/lib/mysql \ -v /root/mysql/init:docker-entrypoint-initdb.d \ -v /root/mysql/conf:/etc/mysql/conf.d \ mysql
使用Dockerfile自定义镜像
自己自定义自己java程序的镜像
- 镜像包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程
dockerFile
Dockerfile是个包含指令的文本文件,用指令来说明要执行什么从操作来构建镜像,让Docker可以根据Dockerfile帮助我们自动构建镜像
相当于封装了我们人工部署JAR包的过程
利用固定的指令来描述镜像的结构和构建过程,让docker依次构建镜像
我们只需要描述好镜像的结构,基础是xx,中间层有哪些层,docker就会自动帮我们完成整个镜像的构建了
常见命令
- FROM
- 指定基础镜像
- 例: FROM centos:6
- ENV
- 设置环境变量,可在后面指令使用
- 例: ENV key value
- COPY
- 拷贝本地文件到镜像的指定目录
- 例:COPY ./jrell.tar.gz /tmp
- RUN
- 执行Linux的shell命令,一般是安装过程的命令
- 例:
RUN tar -zxvf /tmp/jrell.tar.gz && EXPORTS path=/tmp/jrell:$path
- EXPOSE
- 指定容器运行时监听的端口,是给镜像使用者看的
- 例: EXPOSE 8080
- ENTRYPOINT
- 镜像中应用的启动命令,容器运行时调用
- 例: ENTRYPOINT java -jar xx.jar
更全的语法看官方文档
案例
text# 基础镜像 FROM openjdk:11.0-jre-buster # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["java","-jar","/app.jar"]textdocker build -t myImage:1.0-t:给镜像起名
. :指定Dockerfile所在目录,如果就在当前目录,则指定为“.”注意Dockerfile放置的目录要和你拷贝操作设置的逻辑匹配,此处要和被拷贝的那个jar包放一起
-
准备Dockerfile和jar包
-
下载所需的jdk基础镜像
-
进入到Dockerfile所在目录
-
执行指令,部署容器
text# docker build -t 构建出的镜像的名字 . docker build -t docker-demo .指令没有指定的话,Dockerfile文件名就要叫Dockerfile
这里的“.”指定了Dockerfile的路径
检查是否添加上了
textdocker images创建并运行容器
textdocker run -d --name dockerName -p 8080:8080 docker-demo
容器网络互连
默认情况下,所有容器都是以bridge方式连接到Docker的一个虚拟网桥上

这种通过ip相互连接的方式不太好
ip会变,如果另外一个容器先启动、占掉了mysql的之前的ip地址,mysql容器再启动之后ip地址就变化了
优化:自定义网络
常用指令
- docker network create:创建一个网络
- docker network ls:查看所有网络
- docker network rm :删除制定网络
- docker network prune:清除未使用的网络
- docker network connect:使指定容器加入某网络
- docker network disconnect:使指定容器连接离开某网络
- docker network inspect:查看网络详细信息
加入自定义网络之中的容器 可以通过容器名互相访问,不需要知道对方的ip地址

- 如果有同一个网关,就处于同一个网段
同一个网段中的容器是可以互相访问的
-
指令使用
创建自定义网段
textdocker network create heima查看当前的网段
textdocker network ls加入容器
text# docker network connect 网络名 容器名 docker network connect heima mysql或者在创建容器的同时加入网段
textdocker run -d --name dd -p 8080:8080 -network heima docker-demo
DockerCompose部署项目
Docker Compose通过一个单独的docker-compose.yml模版文件来定义一组相关联的应用容器,帮我们实现多个互相关联的Docker容器的快速部署
描述了项目内多个容器及其参数信息
- 运行的时候自动读取这个文件
就能按照这个文件的描述自动创建和运行所需要的容器
语法案例
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: yourPassword
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks:
- example-net
example:
build:
context: .
dockerfile: ./Dockerfile
container_name: blog
ports:
- "8080:8080"
networks:
- example-net
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/usr/share/nginx/html"
- "./nginx/ssl:/etc/nginx/ssl/:ro"
depends_on:
- example
networks:
- example-net
networks:
example-net:
name: example
用docker compose之后,java应用不再需要我们 手动通过docker build构建成镜像,再创建运行容器,网络也不需要自己创建网络,直接在文件里面描述
这里配置了“build: ” “路径”和“Docker“,它就会按照这个路径读取Dockerfile,
备注:按照案例中的路径
docker-compose.yml要和Dockerfile、mysql、nginx、jar包放在一起
- 接着使用docker compose命令构建即可顺利部署
docker compose up -d
实战-使用Docker compose部署
编写docker-compose.yml文件
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: yourPassword
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks:
- example-net
example:
build:
context: .
dockerfile: ./Dockerfile
container_name: example
ports:
- "8080:8080"
networks:
- example-net
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/usr/share/nginx/html"
- "./nginx/ssl:/etc/nginx/ssl/:ro"
depends_on:
- example
networks:
- example-net
networks:
example-net:
name: example
version字段是必需的,而且必须是有效的 Compose 文件版本号(如"3.8"、"3"等)。✅ 建议使用较新的版本,比如
"3.8"或"3.7"。
example容器的内部端口映射应该和你的jar包设置的端口一致(比如 如果java应用用的8080端口,这里内部端口就要设置成8080)
docker-compose.yml的数据库密码要和配置文件一样,不然连接不上
准备好application-prod.yml文件
- 调整host,改为mysql的容器名
- 调整云服务器mysql密码 调整云服务器redis密码
- (修改一些clientId/client-secret 之类的需要配置的东西)
真实项目部署中,数据库不会设置端口映射,都是通过容器名访问 所以后端的jdbc连接要按容器名配置
由激活application-dev.yml改成激活application-prod.yml
后端
编写Dockerfile文件
# 基础镜像
FROM openjdk:8-jre-slim
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
# COPY blog-server-1.0-SNAPSHOT.jar /app.jar
COPY blog-server-*.jar /app.jar
# 入口
ENTRYPOINT ["java","-jar","/app.jar"]
基础镜像视自己项目而定
使用maven的package打包项目成jar包
- 找到父工程
- Lifecysle-package
- jar包在Service模块中的target目录下:blog-service.jar
准备mysql相关文件
进入root目录,然后创建目录
cd /root/
mkdir -p mysql/conf mysql/data mysql/init
/conf
放置
.cnf文件来覆盖或添加 MySQL 的配置项;可能包括字符集设置、缓存大小调整、日志设置等
[client]
default_character_set=utf8mb4
[mysql]
default_character_set=utf8mb4
[mysqld]
character_set_server=utf8mb4
collation_server=utf8mb4_0900_ai_ci
init_connect='SET NAMES utf8mb4'
/data
MySQL 数据库的主要数据存储位置。
- 此目录存放所有 MySQL 数据库的数据文件。当你的数据库中创建表、插入数据等操作时,这些更改都会被保存到此目录下的文件中。
- 通过将这个目录映射到宿主机,即使容器被删除或重新创建,你的数据仍然安全地保留在宿主机上。
/init
用于初始化数据库。
- 在这个目录下,你可以放置一些 SQL 脚本或者 shell 脚本,这些脚本会在 MySQL 容器启动并且没有检测到现有的数据库时自动执行。
- 常见的做法是放置
.sql文件来创建数据库、表或插入初始数据;也可以放置.sh脚本来进行更复杂的初始化操作。
准备nginx相关文件
创建目录
mkdir -p nginx/html
编写.env.production文件
原来的.env.devlopment文件不用删除
Vite 在 不同命令下会自动加载不同的
.env文件:
打包项目
-
我们开发用的脚手架其实就是一个微型服务器,用于:支撑开发环境,运行代理服务器等
-
打包完的文件中不存在:.vue、.jsx、.less等文件,而是:html、css、js等浏览器能识别的文件
-
打包后的文件不借助脚手架运行,而是需要部署到服务器上运行
-
打包前,先梳理好前端项目的ajax封装(请求前缀、代理规则等);
npm run build
打包后会生成dist/build文件夹
/html
目录用于存放 前端静态资源文件,也就是用户通过浏览器访问你的博客时,Nginx 直接返回的 HTML、CSS、JavaScript、图片等内容。
npm run build
然后把 dist/ 里的所有文件复制到部署目录的 nginx/html
最终结构类似
nginx/html/
├── index.html
├── assets/
│ ├── index-abc123.js
│ ├── index-def456.css
│ └── logo.woff2
├── favicon.ico
└── robots.txt
编写nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/json;
sendfile on;
keepalive_timeout 65;
# ========== HTTP 重定向到 HTTPS ==========
server {
listen 80;
server_name yourServerName1 yourServerName2 ...;
# 所有 HTTP 请求 301 永久重定向到 HTTPS
return 301 https://$host$request_uri;
}
# ========== HTTPS 服务 ==========
server {
listen 443 ssl;
server_name yourServerName1 yourServerName2 ...;
# SSL 证书和私钥路径(根据你的实际路径修改)
ssl_certificate /etc/nginx/ssl/example.pem; # 证书链(含中间证书)
ssl_certificate_key /etc/nginx/ssl/example.key; # 私钥文件
# 前端静态资源
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# API 代理
location /api/ {
proxy_pass http://example:8080/; # 注意结尾的 /
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
转发到的容器名和端口和你的实际情况匹配
运行docker-compose.yml
进入文件所在目录,执行
docker compose up -d
查看项目下的所有进程
docker compose ps
如果有失误,
比如mysql初始化失误
text# 1. 停止并删除容器 docker compose down # 2. 删除旧的 MySQL 数据(⚠️ 会丢失所有数据!) sudo rm -rf ./mysql/data/* # 3. (可选)确认 init 目录下是你新改好的 SQL 文件 ls ./mysql/init/ # 4. 重新启动 docker compose up -d如果jar包有问题
text# 换jar包 docker compose down docker compose up -d --build # --build 会强制重新构建镜像,确保用的是新 JAR。
给云服务器添加入方向规则

到这里就差不多了,如果中途遇到其他bug,可以问问ai,更全面的部署上线流程可以看这篇文章
评论 (0)
暂无评论,快来抢沙发吧!