Docker
Docker基础
什么是Docker
- 先理解什么是jar包,java的jar包和docker的镜像比较类似,都是打包好的东西,可移植,区别就是jar包属于半成品,镜像是预制菜,加热下就能吃
- 如果要在一台物理机上运行多个相同的服务,传统的方式是构建多个虚拟机来运行,但是这样特别占用物理资源,资源利用率不大,但是通过docker容器的方式,可以运行数百甚至数千的服务,并且Docker与宿主机系统同级,共用内核系统,运行的服务性能接近直接在物理机上运行
什么是镜像,什么是容器
按等级来说,镜像的等级比容器高,容器是镜像运行的产物,一个镜像可以运行多个容器。镜像就像模具,容器就是用这个模具生产出来的工具
docker镜像基础原理
- 任何docker的应用镜像,本质上都依赖一个底层系统(基础镜像),只是这个底层系统是被精简过的,打包成了镜像格式,只提供应用运行必须的系统环境,应用镜像就是在这个地基(基础镜像)上,叠加了应用程序本身和她的依赖,最终形成一个可独立运行的单元
- 基础镜像(精简版底层系统)+ 应用程序(如nginx)+ 应用依赖的分层文件集合 —- 基础镜像就是那个“被打包成镜像的精简底层系统”,只保留能执行系统服务的二进制文件,能读取文件,使用网络,链接依赖库等,是所有应用镜像的地基
如何构建最小化镜像
最小化镜像的「黄金法则」
- 基础镜像:优先 alpine/distroless/scratch,拒绝臃肿发行版。
- 依赖:构建时用 -dev 依赖,运行时只用运行时依赖,不装无用工具。
- 多阶段:构建和运行彻底分离,只复制最终产物。
- 清理:实时删除中间文件、缓存、符号表,不留冗余。
- 安全:用非 root 用户运行,减少攻击面。
- 减少分层
流程
- 打包镜像image –> 移植到其他电脑 –> 运行镜像
- image是分层的,优点是可复用且节约磁盘空间
镜像与容器相关命令
增
- docker pull/push ubuntu:20.4 拉取/推送ubuntu镜像,后面是标签
- docker build -t myapp:v1 . 构建镜像,后面的点不能省,代表当前目录
- docker save -o myapp.tar myapp:v1 将镜像打包成tar包
- docker load -i myapp.tar 加载tar包
- docker cp /data myapp:/app 将宿主机目录/data 拷贝到镜像myapp的/app目录下,将两个路径互换就是反过来拷贝
删
- docker rm -f ID/names 根据镜像id或镜像名删除镜像
- docker images rm id/name 根据镜像id或镜像名删除镜像
- docker system prune -a 清理docker中未被使用的资源
- docker container prune 删除所有已停止的镜像
改
- docker tag myapp:v2 修改镜像吗myapp的标签为v2
- docker start/stop/kill/restart myapp 启动/停止/杀掉/重启 镜像
查
- docker ps 查看正在运行的镜像,加-a的话可以列出所有镜像
- docker images / docker image ls 列出所有镜像
- docker logs -f mynewapp 根据镜像名/ID实时查看运行日志
- docker inspect myapp 显示镜像详细信息
- docker stats myapp 统计镜像资源使用
其他执行命令
- docker run -d -p 8080:80 [-v /host/data:/app/data] [–name mynewapp] [-e ENV=prod] [–rm] nginx
- -d为后台运行,-p端口映射,前面的8080是宿主机端口,用于用户访问,后面的80是镜像端口;-v是将linux的目录加到镜像目录中,
–name是将本次运行的镜像命名,通过不同命名可以一个镜像跑多个,-e是指定环境变量,–rm是停止后自动删除镜像
- docker -exec -it myapp /bin/bash 进入到镜像里面,这个/bin/bash是容器里面的shell,不是linux的,如果容器里面没有这个shell,那就不能用这个shell
docker网络
说明
docker网络中有三种模式,bridge桥接(对应vm的nat),host(与宿主机共用物理网卡),null 无网络
增
- docker network create –driver=bridge [–subnet=192.168.10.0/24] mynet 创建bridge网络,可自定义私网,加入到创建的网络中的容易可以ping容器名
- docker network create -d macvlan –subnet=192.168.146.0/24 –gateway=192.168.146.2 -o parent=ens33 myvlan 创建macvlan网络,macvlan网络,直接分配mac地址容器像物理设备一样出现在局域网中物理机也可以ping通容器
删
- docker network rm mynet 根据网络名删除
改
- docker network disconnect bridge myapp
- docker network connect myapp
查
- docker network ls 查看所有网络
- docker inspect mysql8 | grep -E “NetworkMode|IPAddress” 查看容器名mysql8的网络信息
执行指令
- docker run -d –network=bridge myapp 将镜像添加到bridge网络中
多阶段构建和一步构建
- 多阶段构建的话再安装依赖等相关环境时,这些依赖只会再构建阶段,在运行时是不存在这些依赖的,大大减少了镜像大小
- 一次性构建就会导致镜像文件包含依赖等相关环境,镜像文件变大
Dockerfile中的指令
在Dockerfile中,指令的大小写风格要一致
- from 指定基础镜像,例:from nginx:alpine
- run 执行命令(linux)命令
- copy 复制文件/目录(主机复制到容器),例:copy ./app /usr/share/nginx/html 主机路径时根据docker build后面的路径来的
- add 类似copy,支持自动解压和远程url,例:add https://example.com/file.tar.gz /data
- cmd 容器启动时执行的命令(可被覆盖),CMD 另一个核心用法是给 ENTRYPOINT 提供默认参数
- entrypoint 容器入口命令,不可被覆盖,必须被执行
- env 设置环境变量(容器运行时使用)
- arg 定义构建时的变量(构建时使用,构建完消失)
- workdir 设置工作目录,后续命令的操作路径,相当于cd,例:workdir /app
- user 指定执行命令的用户
- volume 定义数据挂载点
- label 添加元数据
- healthcheck 定义容器健康检查,例:healthcheck –interval=30s cmd curl -f http://localhost/
- onbuild 延迟执行命令(当本镜像作为其他镜像的基础时触发)
- shell 覆盖默认的shell,例:shell[“/bin/bash”,”-c”]
- stopsingal 设置停止容器信号
docker搭建Ruoyi前后端项目
创建自定义网络,让容器加入到一个镜像内
docker network create –driver=bridge [–subnet=192.168.1.0/24] ruoyi-net
mysql
- 拉取镜像docker pull mysql:8.0
- 运行镜像,docker run -d -p 3306:3306 –name mysql –network ruoyi-net -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=ruoyi-vue-pro -v /root/mysql-data:/var/lib/mysql –restart always mysql:8.0
- 进入数据库
1
2docker exec -it mysql bash #进入容器
mysql -uroot -p - 导入数据,有两种方法
- 手动导入,将sql文件拷贝到容器中 docker cp /root/sql/quartz.sql mysql:/tmp,然后根据第三步进入容器,执行mysql -uroot -p ruoyi-vue-pro < quartz.sql, 将两个sql文件都导入进去
- 自动导入,将数据库文件在docker run时-v挂到/docker-entrypoint-initdb.d下,容器初始化时会自动读取
redis
- 拉取镜像 docker pull redis:7.2
- 运行镜像
docker run -d -p 6379:6379 --network ruoyi-net --name redis -v /root/redis-data:/data --restart always redis:7.2 redis-server --requirepass "redis123" --bind 0.0.0.0 - 进入redis
1
2docker exec -it redis bash #进入容器
redis-cli
ruoyi-java
- 拉取源码,git clone https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
- 修改application-local.yaml文件,将里面的mysql和redis写成容器名,不用写ip
- 编写Dockerfile文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#第一阶段
FROM maven:3.8.6-jdk-8 AS builder
COPY settings.xml /root/.m2/settings.xml
COPY ruoyi-vue-pro /ruoyi-vue-pro
WORKDIR /ruoyi-vue-pro
RUN mvn clean install package '-Dmaven.test.skip=true'
#第二阶段:运行
#FROM amazoncorretto:8-alpine
FROM eclipse-temurin:8-jre
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
COPY --from=builder /ruoyi-vue-pro/yudao-server/target/yudao-server.jar yudao-server.jar
#JVM内存优化参数(根据实际情况调整)
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
# 健康检查(Spring Boot Actuator 需配置)
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl http://localhost:48080 || exit 1
# 启动命令(支持传递额外参数)
ENTRYPOINT exec java $JAVA_OPTS -jar yudao-server.jar $0 $@ - 创建settings.xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
</settings> - 记得将上面的源码,Dockerfile,xml文件放在同一个目录下,最好创一个目录放着三个
- 构建镜像 docker build -t –no-cache ruoyi-java:v1 .
- 运行镜像并查看日志 docker run -d -p 48080:48080 –network ruoyi-net –name ruoyi-java ruoyi-java:v1 && docker logs -f ruoyi-java
mini_nginx
- 这个是用来给前端运行的基础镜像
- 编写Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84from alpine:3.19 as builder
run sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add --no-cache \
build-base \
linux-headers \
pcre-dev \
zlib-dev \
openssl-dev \
wget \
tar
arg NGINX_VERSION=1.26.3
run wget -q https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
tar -zxf nginx-${NGINX_VERSION}.tar.gz && \
rm nginx-${NGINX_VERSION}.tar.gz
workdir /nginx-${NGINX_VERSION}
run ./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-threads \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--without-http_autoindex_module \
--without-http_ssi_module \
--without-mail_pop3_module \
--without-mail_imap_module \
--without-mail_smtp_module \
--without-http_scgi_module \
--without-http_uwsgi_module \
--without-http_fastcgi_module \
--with-cc-opt="-Os -fomit-frame-pointer -g" \
--with-ld-opt="-Wl,--as-needed" && \
make -j $(nproc) && make install && mkdir -p /usr/lib/nginx/modules && \
strip /usr/sbin/nginx
from alpine:3.19
run sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add --no-cache \
pcre \
zlib \
openssl \
tzdata && addgroup -S nginx && adduser -S -D -H -s /sbin/nologin -G nginx nginx && \
mkdir -p /var/cache/nginx && \
mkdir -p /var/log/nginx && \
mkdir -p /usr/share/nginx/html && \
echo 'My mini Nginx' > /usr/share/nginx/html/index.html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /usr/share/nginx/html
copy --from=builder /usr/sbin/nginx /usr/sbin/nginx
copy --from=builder /etc/nginx /etc/nginx
copy --from=builder /usr/lib/nginx/modules /usr/lib/nginx/modules
copy nginx.conf /etc/nginx/nginx.conf
#copy default.conf /etc/nginx/conf.d/default.conf
copy yudao.conf /etc/nginx/conf.d/yudao.conf
expose 80
healthcheck --interval=30s --timeout=3s \
cmd wget -q --spider http://localhost/ || exit 1
cmd ["nginx", "-g" ,"daemon off;"] - 编写default.conf nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44### default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
### nginx.conf
ser nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server_tokens off;
include /etc/nginx/conf.d/*.conf;
} - 构建镜像 docker build -t mini_nginx:v1 .
yudao前端
- 创建一个目录,用来放前端构建镜像的文件,进入目录
- 拉取源码 git clone https://gitee.com/yudaocode/yudao-ui-admin-vue3.git
- 修改那三个配置文件
- 编写Dockerfile文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from node:20-alpine as build
workdir /app
copy yudao-ui-admin-vue3 ./
run npm config set registry https://registry.npmmirror.com/ \
&& npm install -g pnpm@8.15.5 \
&& pnpm install
run npm run build:prod
from mini_nginx:v1
run rm -rf /var/www/*
copy --from=build /app/dist-prod /var/www/dist-prod
copy ruoyi.conf /etc/nginx/conf.d/default.conf
expose 80
cmd ["nginx", "-g","daemon off;"] - 编写nginx配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24server {
listen 80;
charset utf-8;
server_name _;
location / {
root /var/www/dist-prod;
index index.html index.hml;
}
location /login?redirect=/index {
root /var/www/dis-prod;
index index.html index.hml;
}
location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.146.139:48080地方/; #这里面的ip可以写成容器名
}
} - 构建镜像 docker build -t yudao:v1 .
- 运行镜像 docker run -d -p 80:80 –network ruoyi-net –name yudao yudao:v1






