Docker镜像制作方式
文章目录
前言
在阅读这篇文章之前,您需要了解docker容器的基本概念,以及容器启动、数据卷等基础知识;
跟文章主要介绍Docker镜像的创建方式,其中Dockerfile创建镜像使用的最多,也最为重要,本博客会重点讲解;
文章最后,附上Dockerfile实践教程,强化对Dockerfile构建镜像的理解;
一、通过快照生成镜像
1.1 案例说明
我们用公共的nginx镜像,把它的默认界面改成hello blog,然后重新推送成镜像,查看是否制作成功
1.2 制作步骤
1、拉取镜像
docker pull nginx:latest
2、运行镜像
docker run --name n1 -itd nginx:latest
3、进入容器
docker exec -it n1 bash
4、修改界面:
cd /usr/share/nginx/html/
cat > index.html<<EOF
> hello blog
> EOF
cat index.html
hello blog
5、将容器提交为镜像
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
432b9375dc46 nginx:latest "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 80/tcp n1
# -a作者信息 -m 镜像信息
docker commit -a 'hyy hahaha' -m 'my nginx image' n1 nginx_hello_blog:v1
sha256:bffe7f45cbcdb1fc2e65a69d8fe53c96cbaedc42a1115a65266a1297895e48bb
docker images '*blog*'
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_hello_blog v1 bffe7f45cbcd 15 seconds ago 161MB
1.3 快照生成镜像的优缺点
优点:
- 生成速度快,比较灵活
缺点:
- 镜像体积:生成镜像可能包含容器的临时信息
- 不易维护:构建历史无法追踪,除了问题不好排查
二、Dockerfile制作镜像
1、 概述
Dockerfile制作镜像,方式是创建一个名为Dockerfile的文件,通过特定语法定义镜像的构建步骤。这种方式优点是构建过程透明,易于排查问题,且有具体的构建脚本(Dockerfile)可以进行版本控制(如git),方便团队协作;
接下来我会讲解Dockerfile的语法和使用,一步步讲透它是如何构建镜像的~~
2、 Dockerfile命令
2.1 CMD 与 ENTRYPOINT
2.2 概述&语法
两者都能指定容器启动时(docker run)需要执行的一个命令。
语法格式:
exec格式:
CMD ["命令", "参数1", "参数2" ,...]
ENTRYPOINT ["命令", "参数1", "参数2" ,...]
shell格式:
CMD 命令 参数1 参数2 ...
ENTRYPOINT 命令 参数1 参数2 ...
2.3 CMD和ENTRYPOINT的区别
1、 两个指令同时存在时(虽然语法不限制,但CMD建议在后),CMD中的的参数会作为ENTRYPOINT的参数;
实际案例:
Dockerfile:
-------------------------------------------
FROM nginx:latest
WORKDIR /app
COPY ./a.txt ./a/a.txt
COPY ./b.txt ./b/b.txt
ENTRYPOINT ["ls"] #运行的命令
CMD ["-lh", "/app/a"] #ls命令的参数 预期应该显示a.txt
--------------------------------------------
docker build -t n1:v1 .
docker run -it n1:v1
total 0
-rw-r--r-- 1 root root 0 Feb 27 05:39 a.txt
2、CMD命令会被docker run后面的参数覆盖,但是ENTRYPOINT不会被覆盖。
实际案例:
Dockerfile:
-------------------------------------------
FROM nginx:latest
WORKDIR /app
COPY ./a.txt ./a/a.txt
COPY ./b.txt ./b/b.txt
#后续docker run添加参数,会直接成为ENTRYPOINT(ls)的参数
ENTRYPOINT ["ls"]
# 若后续docker run 不添加启动命令,预期应该显示a.txt
CMD ["哈哈我是要被覆盖的参数"]
--------------------------------------------
docker build -t n1:v1 .
docker run -it --name container_name n1:v1
total 0
-rw-r--r-- 1 root root 0 Feb 27 05:39 a.txt
docker rm container_name
# CMD命令将被完全覆盖 当前启动命令等价于: ls -lh /app
docker run -it --name container_name n1:v1 -lh /app
total 8.0K
drwxr-xr-x 2 root root 4.0K Feb 27 05:51 a
drwxr-xr-x 2 root root 4.0K Feb 27 05:51 b
2.4 exec/shell格式说明
两种格式,建议用哪个?
先说观点:非特殊情况下,建议统一用exec格式。
原因如下:
shell格式下,docker会自动把CMD后面的命令封装起来,例如这样:/bin/sh -c "我是CMD传递的命令"。这会导致 CMD和ENTERPOINT在传参时很可能出现异常;
我们用一个实际例子演示一下:
Dockerfile:
-------------------------------------------
FROM nginx:latest
WORKDIR /app
COPY ./a.txt ./a/a.txt
COPY ./b.txt ./b/b.txt
ENTRYPOINT ["ls"]
CMD /app/b #预期应该显示b.txt(但实际不会这么显示)
--------------------------------------------
docker build -t n1:v1 .
docker run -it n1:v1
/bin/sh
/app/b:
b.txt
# 上面显示的内容其实等价于: ls /bin/sh -c "/app/b"
# 我们用一个新的全新的没有entrypoint和cmd的容器演示一下:
Dockerfile:
------------------
FROM nginx:latest
WORKDIR /app
COPY ./a.txt ./a/a.txt
COPY ./b.txt ./b/b.txt
------------------
docker build -t n1:v1 .
docker run -it n1:v1 ls /bin/sh -c "/app/b"
/bin/sh
/app/b:
b.txt
# 可以看到和刚才输出的一摸一样!
2.5 exec格式,如何设置环境变量
exec格式不能像shell格式那样,自动解析$ENV_NAME
但是我们可以通过/bin/sh -c来实现:
Dockerfile:
---------------------
ENTRYPOINT ["sh", "-c", "ls -lh | grep $DIR_NAME"]
---------------------
2.2 FROM
2.2.1 概述
在制作镜像时,指定一个基础镜像,在这个基础上进行制作。
注意点:
- from指定后,先在本地主机查找指定镜像,没有去远程仓库查找,还是没有,返回构建失败信息;
- 可以不指定镜像版本,docker默认设置查找版本为
latest - 一个Dockerfile可以有多个FROM;
- FROM必须在非注释行或者ARG后的第一个命令
2.2.2 语法
FROM [--platform=<platform>] <image>[:<tag>] [AS <new_name>]
- < platform>: 构建的 cpu 架构,如 linux/amd64, linux/arm64
- < image>: 指定的基础镜像
- < tag>: 镜像标签(版本)
- <new_name>: 指定构建步骤的名称,配合COPY --from=<new_name>可以实现多级构建
2.3 ENV
2.3.1 概述
ENV可以设置一个或者多个环境变量,提供给ENV后续的指令(如ENV、ADD、COPY)使用,格式为${evn_name}或$env_name;
注意 :不止镜像构建期间,容器运行时,这些环境变量仍然可以使用!
2.3.2 语法
ENV <key>=<val> ...
2.3.3 演示
Dockerfile:
----------------------
FROM nginx:latest
ENV ENV1="1" ENV2="2"
----------------------
docker build -t n1:v1 .
docker run -itd --name n1 n1:v1
docker exec n1 env | grep ENV
ENV1=1
ENV2=2
2.4 ARG
2.4.1概述
ARG类似ENV,与ENV最大区别是ARG只能在镜像构建阶段使用。
注意:
- Dockerfile中,可以不指定ARG的
val,可以用docker build --build-arg key=val,key-val指定; - ENV和ARG同时存在
ENV会覆盖ARG - Dockerfile可以包含一个或多个ARG
2.4.2 语法
ARG <name>[=default_name]
2.4.3 演示
Dockerfile:
---------------------------------------------
ARG PYTHON_VERSION
FROM python:${PYTHON_VERSION}-slim
ARG REQUEST_VERSION=2.31.0
RUN pip install requests==${REQUEST_VERSION}
---------------------------------------------
docker build -t python:v1 --build-arg PYTHON_VERSION=3.9 .
[+] Building 0.1s (6/6) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 168B 0.0s
=> WARN: InvalidDefaultArgInFrom: Default value for ARG python:${PYTHON_VERSION}-slim results in empty or invalid base image name (line 2) 0.0s
=> [internal] load metadata for docker.io/library/python:3.9-slim 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/2] FROM docker.io/library/python:3.9-slim 0.0s
=> CACHED [2/2] RUN pip install requests==2.31.0 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:2f606c91b58880c79fe959b6b3f504889c3fc11f0ae9f1b917c95b67d7809212 0.0s
=> => naming to docker.io/library/v1:v1 0.0s
# 如果ARG不设置值,会有警告,所以建议给ARG设置一个默认值
2.5 LABEL
2.5.1 概述
为镜像提供可以阅读的标签(描述该镜像的信息),键值对结构
2.5.2 语法
LABEL <key>=<value> <key>=<value> <key>=<value> ...
2.5.3 演示
Dockerfile:
----------------------------------
FROM ubuntu:latest
LABEL author="hyy" \
description="up"
----------------------------------
docker build -t linux:v1 .
docker inspect linux:v1 | 过滤"Labels"
"Labels": {
"author": "hyy",
"description": "up",
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "24.04"
},
2.6 COPY
2.6.1 概述
功能:把宿主机文件或目录复制到镜像中指定路径
2.6.2 语法:
COPY [chown=<user>:<group>] src1 [src2 src3...] target
- user和group分别是用户和用户组;
- src和target可以是文件,也可以是目录;
- src支持通配符,若src是目录或者通配符,target必须也是目录,并且最后必须
/结尾; - target不存在会自动创建;
- target默认为
WORKDIR指定的路径,也可以设置为绝对路径; - src默认为项目路径,也就是Dockerfile所在路径(非父目录),也可以填写绝对路径;
COPY可以搭配--from< name>实现多级构建,本博客专栏后续会分一个主题讲解;
2.6.3 演示
Dockerfile:
----------------------------------------
FROM busybox:latest
WORKDIR /app
# 把test.txt复制到镜像/app路径下,该命为file,并且设置用户/用户组为nobody(busybox镜像自带的一个用户/用户组)
COPY --chown=nobody:nobody ./test.txt ./file.txt
# 把项目路径下所有文件、目录草被到镜像/app/dir中
COPY ./ ./dir/
# 把项目当前目录层级下,所有txt文件(不包含子目录) 和 Dockerfile文件拷贝到镜像/aprent目录下
COPY *.txt Dockerfile /parent/
----------------------------------------
项目结构:
ls -lh
total 16K
drwxr-xr-x 2 root root 4.0K Mar 4 10:07 dir1
-rw-r--r-- 1 root root 135 Mar 4 10:22 Dockerfile
-rwsrwxrwx 1 root root 32 Mar 4 09:48 run.txt
-rws------ 1 root root 15 Mar 4 09:48 test.txt
ls -lh dir1
total 8.0K
-rw-r--r-- 1 root root 2 Mar 4 10:06 a.txt
-rw-r--r-- 1 root root 2 Mar 4 10:07 b.txt
构建镜像+启动容器+查看效果:
docker build -t n1:v1 .
docker run -itd --name n1 n1:v1
docker exec -it n1 sh
/app # ls -lh
total 8K
drwxr-xr-x 3 root root 4.0K Mar 4 02:22 dir
-rws------ 1 nobody nobody 15 Mar 4 01:48 file.txt
/app # ls -lh dir
total 16K
-rw-r--r-- 1 root root 135 Mar 4 02:22 Dockerfile
drwxr-xr-x 2 root root 4.0K Mar 4 02:07 dir1
-rwsrwxrwx 1 root root 32 Mar 4 01:48 run.txt
-rws------ 1 root root 15 Mar 4 01:48 test.txt
/app # ls -lh ../parent/
total 12K
-rw-r--r-- 1 root root 135 Mar 4 02:22 Dockerfile
-rwsrwxrwx 1 root root 32 Mar 4 01:48 run.txt
-rws------ 1 root root 15 Mar 4 01:48 test.txt
2.7 ADD
2.7.1 概述
功能:
和COPY基本无差别,但是ADD更“智能”,针对特殊压缩文件如tar文件和url它可以自动解压、下载到镜像指定目录;
局限性:
ADD虽然看上去更“智能”,但是不推荐用,特别是一些需要解压、或者资源下载的场景。因为它的“智能”,很有限,只能针对tar文件解压,别的类型比如gz,无法进行压缩。
此外下载和解压这个操作不够透明,不利于问题排查;
2.7.2 语法
COPY [--chown=<user>:<group>] src1 [src2 src3 ...] target
- < src>:要复制的源文件、url、压缩文件、文件路径
- < target>:目标路径
-< user>和< group>: --chown更改用户组,分别是所属用户和用户组
2.7.3 演示
2.7.3.1 案例介绍
- dockerfile添加一个显示版本号的环境变量
- dockerfile指定工作目录
- dockerfile配置一个
COPY(复制普通文件)和ADD(自动解压一个文件)对比演示 - 通过简单的python脚本,查看环境变量、copy的文件和解压的文件
2.7.3.2 效果演示
项目结构:
ls -lh
total 16K
-rw-r--r-- 1 root root 889 Mar 4 11:00 app.py
-rw-r--r-- 1 root root 134 Mar 4 10:54 Dockerfile
-rw-r--r-- 1 root root 34 Mar 4 10:52 file.tar
-rw-r--r-- 1 root root 5 Mar 4 10:52 haha.txt
关于tar归档文件的获取:
- 可以通过
tar -zcvf file.tar file.txt把file.txt归档并且压缩(linux自带)- -z是压缩,默认归档后不压缩(底层用gzip命令进行压缩,也是linux原生支持的);
- -c是创建一个归档文件;
- -v是查看详细执行过程;
- -f是指定文件名称
Dockerfile:
FROM python:3.9-slim
ENV MY_VERSION=V1.1
WORKDIR /app
COPY ./haha.txt ./haha.txt
ADD ./file.tar ./
#通过CMD容器启动时,执行python app.py脚本,查看容器构建效果
CMD ["python", "app.py"]
app.py:
import os
import sys
print(">>> 容器应用正在启动...")
# 1. 演示 ENV (读取环境变量)
env_val = os.getenv("MY_VERSION", "未知")
print(f"[ENV 演示] 当前应用版本: {env_val}")
# 2. 演示 WORKDIR (显示当前路径) get current work dir(getcwd)
print(f"[WORKDIR 演示] 当前工作目录: {os.getcwd()}")
# 3. 演示 COPY (读取普通文件)
try:
with open("haha.txt", "r") as f:
print(f"[COPY 演示] 读取 haha.txt: {f.read().strip()}")
except:
print("[COPY 演示] 失败:找不到 haha.txt")
# 4. 演示 ADD (读取自动解压的文件)
try:
# 注意:ADD 解压后会保留目录结构
with open("file.txt", "r") as f:
print(f"[ADD 演示] 读取解压文件: {f.read().strip()}")
except FileNotFoundError:
print("[ADD 演示] 失败:文件没解压成功")
print(">>> 应用执行完毕,准备退出。")
print("="*30)
启动容器,查看效果:
docker build -t py1:v1 .
docker run -it --name p1 py1:v1
==============================
>>> 容器应用正在启动...
[ENV 演示] 当前应用版本: V1.1
[WORKDIR 演示] 当前工作目录: /app
[COPY 演示] 读取 haha.txt: haha
[ADD 演示] 读取解压文件: I`m file.tar
==============================
2.8 VOLUME
2.8.1 概述
功能:
指定镜像中的一个挂载点(挂载到宿主机),类型是匿名卷(不指定名字,名字由docker自行赋予的管理卷)
小提示:
在现代项目中,一般不通过Dockerfile指定挂载点,只是用来避免程序员忘记这回事,声明一下某个路径需要挂载到宿主机;
因为它无法灵活指定关在类型,只能挂载匿名卷;最佳实践是在docker-compose.yml中配置
2.8.2 语法:
VOLUME ["镜像中需要挂载的路径"]
注意:
- 若docker run -v设置了同一个路径的挂载,那么Dockfile将不会创建对应匿名卷;
- docker rm删除容器后,挂载点不会被删除;
- 若容器中指定路劲已有数据,这些数据会自动覆盖到宿主机匿名卷中;
2.8.3 演示
项目结构:
ls -lh
total 8.0K
-rw-r--r-- 1 root root 184 Mar 4 14:58 Dockerfile
-rw-r--r-- 1 root root 273 Mar 4 14:55 init.sql
Dockerfile
FROM mysql:5.7 #设置基础镜像
# 设置维护人信息,可选
LABEL maintainer="hyy@blog.cn"
# 显式声明匿名卷,用于保存自定义日志等
VOLUME ["/var/log/mysql"]
#设置mysql密码,不建议dockerfile中配置,可以docker run的时候配置密码
ENV MYSQL_ROOT_PASSWORD=111
# 设置初始化表数据的sql,docker-entrypoint-initdb.d/是mysql镜像官方指定的数据
COPY ./init.sql /docker-entrypoint-initdb.d/
#官方默认的启动命令,不加也可以
CMD ["mysqld"]
init.sql:
CREATE DATABASE IF NOT EXISTS my_test_db; --创建一个数据库
USE my_test_db;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); --创建一个user表
INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('DockerMaster'); #插入三条数据
启动容器,查看效果:
docker volume ls
DRIVER VOLUME NAME
docker build -t n1:v1 .
docker run --name n1 -e MYSQL_ROOT_PASSWORD=222 -itd n1:v1
docker volume ls
DRIVER VOLUME NAME
local 462ae60a04a1e5d6ccf40cc6cea0dcf7fcc24907e869a37c29b119ec90bf5597
# 下面这个路径是我们宿主机挂载的数据库my_test_db的元数据
ls -lh /var/lib/docker/volumes/462ae60a04a1e5d6ccf40cc6cea0dcf7fcc24907e869a37c29b119ec90bf5597/_data/my_test_db
total 112K
-rw-r----- 1 lxd docker 65 Mar 4 15:08 db.opt
-rw-r----- 1 lxd docker 8.5K Mar 4 15:08 users.frm
-rw-r----- 1 lxd docker 96K Mar 4 15:08 users.ibd
2.9 HEALTCHECK
2.9.1 概述
用于检测容器是否正常工作;
Dockerfile的HEALTCHECK和docker-compose的healtcheck是等价的,只是docker-compose优先级更大,如果两个地方都配置了健康检查,则docker-compose的健康检查会覆盖Dockerfile。
2.9.1 语法
#通过command命令,检查容器是否健康,健康,返回0
HEALTCHECK [options] CMD command
#禁用来自基础镜像的健康检查
HEALTCHECK NONE
options(和docker-compose的配置是一样的):
- –start-period=等待启动时间(默认0s):等容器启动后指定时间后,再进行探测检查,给它一个缓冲时间,避免无效检查;
- interval=延迟时间(默认30s):间隔30s检查一次;
- timeout=超时时间(默认30s):超时后,认为这次检查容器不健康(返回1);
- retries=重试次数(默认3此):重试指定次数后,仍然不健康,直接启动报错;
2.9.2 演示
Dockerfile:
#官方nginx镜像,基于debain系统
FROM nginx:latest
# 替换为阿里云 Debian(Nginx容器用的debian) 镜像源(解决国内下载慢/失败问题)---直接拷贝过来就行
RUN echo "deb http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" > /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian/ bookworm-backports main non-free contrib" >> /etc/apt/sources.list && \
echo "deb-src http://mirrors.aliyun.com/debian/ bookworm main non-free contrib" >> /etc/apt/sources.list && \
echo "deb-src http://mirrors.aliyun.com/debian/ bookworm-updates main non-free contrib" >> /etc/apt/sources.list && \
echo "deb-src http://mirrors.aliyun.com/debian/ bookworm-backports main non-free contrib" >> /etc/apt/sources.list && \
echo "deb http://mirrors.aliyun.com/debian-security/ bookworm-security main non-free contrib" >> /etc/apt/sources.list && \
echo "deb-src http://mirrors.aliyun.com/debian-security/ bookworm-security main non-free contrib" >> /etc/apt/sources.list
# 替换 Debian 官方源为阿里云源(解决超时问题),并给nginx容器安装 curl
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources 2>/dev/null || true && \
apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
# 可写可不写:声明 Nginx 默认端口
EXPOSE 8080
# 启动 Nginx(前台运行,保证容器不退出)
CMD ["nginx", "-g", "daemon off;"]
# 用curl这个命令进行健康检查,理论上9090端口会报错,所以一段时间后,启动的容器会显示unhealthy
HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
CMD curl -fs 127.0.0.1:9090 || exit 1
构建/启动容器,查看效果:
docker build --no-cache -t n1:v1 .
docker run --name n1 -itd n1:v1
#大概20s后
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f3362f7cc128 n1:v1 "/docker-entrypoint.…" About a minute ago Up About a minute (unhealthy) 80/tcp, 9090/tcp n1
2.10 USER
2.10.1 概述
用于指定运行镜像时,以及在其后的 RUN、CMD 和 ENTRYPOINT 指令中使用的用户名(或 UID)和可选的用户组(或 GID)。
在 Docker 中,容器默认以 root 权限运行。为了系统安全(遵循“最小权限原则”),生产环境中强烈建议创建一个非特权用户,并使用 USER 指令切换到该用户来运行应用程序,以防止容器内的恶意进程通过漏洞获取宿主机的最高权限。
2.10.2 语法
# 通过用户名和(可选的)用户组指定
USER <user>[:<group>]
# 通过 UID 和(可选的)GID 指定(推荐做法,更精确)
USER <UID>[:<GID>]
注意:
- 在使用
USER切换用户之前,该用户或 UID 必须已经存在于镜像中(通常需要先用RUN命令通过useradd创建)。 - 如果只指定了用户或 UID,而没有指定用户组,则默认使用
root组或该用户的默认主组。
2.10.3 使用场景
- 提升安全性:防止应用漏洞导致提权,限制进程只能访问特定的资源。
- 满足平台合规要求:许多企业级容器编排平台(如 Kubernetes 的 PodSecurityPolicies、OpenShift 等)强制要求容器不能以 root 身份运行。
- 文件权限隔离:限制应用程序只能读写它自己专属的目录,避免误操作或恶意修改基础环境文件。
2.10.4 演示
Dockerfile:
# 基于 alpine 镜像
FROM alpine:latest
# 1. 创建一个名为 appuser 的普通用户和名为 appgroup 的组
# alpine 中使用 addgroup 和 adduser
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 2. 创建应用工作目录
WORKDIR /app
# 3. 将 /app 目录的所有权交给 appuser(重要!否则切换用户后可能无法写入该目录)
RUN chown -R appuser:appgroup /app
# 4. 切换到非 root 用户 appuser
USER appuser
# 5. 验证:启动容器时执行命令查看当前用户
CMD ["whoami"]
小提示:权限与用户的那些事儿
在编写 Dockerfile 并尝试切换非 root 用户时,我们经常会用到adduser -S和chown -R,它们背后的含义如下:
1.adduser -S中的-S(System)
它代表创建一个 “系统用户” 。系统用户具有以下三个特点,完美契合 Docker 的“最小权限”安全理念:
- 专为运行程序而生:它专门用来在后台运行应用程序(如 Java/Node.js 服务),而不是给真实人类交互使用的。
- 被剥夺登录权限:它默认没有密码,也没有正常的终端 Shell 环境,这意味着黑客即使拿到该账号也无法登录系统。
- 专属低权 ID:系统会为其分配一个专属的较小 UID(通常小于 1000),与普通用户的 ID 区分开,严格限制其系统级特权。
2.
chown -R中的-R(Recursive)
它代表 “递归” 操作。
构建/启动容器,查看效果:
# 1. 构建镜像
docker build -t user-test:v1 .
# 2. 运行容器(--rm 表示运行结束后自动删除容器),查看输出
docker run --rm user-test:v1
# 输出结果:
appuser
(说明:控制台输出结果为 appuser 而不是 root,证明后续的指令和容器启动进程都已降级为普通用户执行,达到了安全隔离的目的。)
更多推荐


所有评论(0)