Debian下Docker安装及使用
Docker 安装
注意!, Docker默认使用iptables来管理分配容器网络部分, 其他防火墙可能不管用(群晖就没用iptables, 有关防火墙的部分得走系统防火墙进行配置)
下载Docker和Docker-compose的可执行文件: Docker & Docker-compose
# 下载二进制文件压缩包
wget https://download.docker.com/linux/static/stable/x86_64/docker-27.5.0.tgz
# 解压压缩包
tar -zxvf docker-27.5.0.tgz
# 将解压后的二进制文件移至/usr/bin/
sudo cp docker/* /usr/bin/
# 编辑配置文件
sudo vim /etc/systemd/system/docker.servicedocker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock --selinux-enabled=false --default-ulimit nofile=65536:65536
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target# 给予运行权限
sudo chmod +x /etc/systemd/system/docker.service
# 载入docker.service
sudo systemctl daemon-reload
# 启动docker服务
sudo systemctl enable docker
sudo systemctl start docker
# 下载docker-compose二进制文件
wget https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-linux-x86_64
# 修改名称
mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
# 给予执行权限
chmod +x /usr/local/bin/docker-composeDocker基础命令
docker pull
pull
# 拉取镜像
docker pull docker.io/library/nginx:latest
## docker.io 镜像服务器地址 官方地址
## library 用户名 library是专门给上有软件提供商官方使用的命名空间
## nginx 仓库名
## latest 选择版本
docker pull nginx # 与上述等效, 只有官方提供最新版本才能这么用
# 可选项
-a # 获取仓库中的所有镜像
--disable-content-trust # 取消镜像内容校验
--registry-mirror=proxy_URL # 指定镜像代理服务地址docker image
image
images/ls
# 查看已下载镜像
docker image ls
docker images # 与上等价
## REPOSITORY 仓库
## TAG 标签
## IMAGE ID ID
## CREATED 时间
## SIZE 大小
# 可选项
-a # 列出所有镜像文件, 包括临时文件
--digests=true # 列出镜像数字摘要值
-f # 过滤列出的镜像, 不会用!!!
--no-trunctrue=true # 对输出结果中太长部分进行截断
-q # 仅输出ID信息inspect
# 查看镜像详细信息
docker [image] inspect ubuntu:20.04
## 返回JSON格式的消息
## 可使用-f {{}}进行筛选rmi/rm
# 删除镜像
docker image rm ubuntu:20.04
docker rmi ubuntu:20.04 # 与上等价
# 可选项
-f # 强制删除镜像, 即使有容器依赖
-no-prune # 不要清理未带标签的父镜像prune
# 清理无用/临时镜像
docker image prune
# 选项
-a # 清理所有无用镜像
-filter filter # 清理符合给定过滤器镜像
-f # 强制删除镜像build
# 基于Dockerfile创建镜像
docker [image] build -t Dockerfile .
# 可选项
--target set_name # 构建到set_name阶段停止
--progress=plain # 查看标准输出save
# 导出镜像文件
docker [iamge] save -o docker_ubuntu_20.04.tar ubuntu:20.04
# -o 导出到指定文件中
docker save ubuntu:20.04 > docker_ubuntu_20.04.tar # 与上等价load
# 从文件导入镜像
docker [image] load -i docker_ubuntu_20.04.tar
# -i 指明文件
docker load < docker_ubuntu_20.04.tarpush
# 注册dockerhub账号
https://hub.docker.com
# 登录dockerhub
docker login -u dfwhy
dckr_pat_suyaZ_4ArOClsaMREX_m7RqCKS0
# 命名为docker.io/user/image:tag格式
docker tag myubuntu:20.04 test_user/myubuntu:20.04
# 上传镜像
docker [image] push test_user/myubuntu:20.04
# 退出登录
docker logoutdocker container
container
commit
# 基于已有容器创建镜像
docker [container] commit ubuntu_test ubuntu:20.04_test
# 选项
-a/--author "" # 作者信息
-c command # 提交时执行Dockerfile指令
-m/--message "" # 提交信息
-p # 提交时暂停容器运行import
# 导入镜像
docker [container] import file|URLcreate
# 创建容器
docker [container] create -itd ubtuntu:20.04
# 可选项start
# 启动容器
docker [container] start ubuntu_testrun
# 创建并启动容器
docker [container] run -itd --name ubuntu_test ubuntu:20.04
# 等价于
docker create --name ubuntu_test && docker start ubuntu_test
# 可选项
-mount type=binf,source=/webapp,destination=/opt/webapp
-v /webapp:/opt/webapp # 与上等价
## 支持三种类型数据卷
### volume 普通数据卷, 映射至主机路径下
### bind 绑定数据卷, 映射到主机指定路径下
### tmpfs 临时数据卷, 只存在内存中
-t \ # docker分配一个伪终端并绑定至容器标准输入上
-i \ # 保持容器的标准输入打开
-d \ # 后台运行容器
--mount source=volume_name,target=mount_path \ # 加载数据卷到指定位置
-mount type=bind,source=目标文件夹,target=挂载文件夹,readonly \ #挂载主机目录至容器目录
--network networkname \ # 指定网络
--dns dns_ip \ # 指定dns服务器
--bridge bridge_name \ # 指定挂载网桥名称
--bip CIDR \ # 指定docker0的掩码???
--host SOCKET \ # Docker服务端接收命令的通道???
--ice true|false \ # 是否支持容器间通信
--ip-forward true|false \ # 容器间通信???
--iptables true|false \ # 是否允许Docker添加iptables规则
--mtu BYTES \ # 容器中的MTU?
--cap-add NET_ADMIN \ # 容器添加创建网卡的权限(wireguard)会用到logs
# 查看容器输出
docker [container] logs ubuntu_test
# 可选项
-details # 打印详细信息
-f # 持续保持输出
-since string # 输出从某个时间开始的日志
-tail string # 输出最近的日志
-t # 显示时间戳信息
-until string # 输出某个时间前的日志pause
# 暂停容器
docker [container] pause ubuntu_testunpause
# 恢复暂停容器
docker [container] unpause ubuntu_teststop
# 终止容器
docker [container] stop ubuntu_test
# 较温和停止, 若超过10s仍未停止则默认执行killkill
# 强行终止容器
docker [container] kill ubuntu_testprune
# 清除所有停止的容器
docker container prunerestart
# 先终止容器再启动容器
docker [container] restart ubuntu_testattach
# 进入容器进行操作
docker [container] attach ubuntu_test
# 可选项
--no-stdin=true|false # 是否关闭标准输入, 默认打开exec
# 创建一个bash进程, 并进入容器
docker -it [container] exec ubuntu_test bashrm
# 删除容器
docker [container] rm ubuntu_test
# 可选项 未测试过!!!
-f # 强制删除运行中容器
-l # 删除容器的连接, 但保留容器
-v # 删除容器挂载的数据卷export
# 导出容器
docker [container] export -o ubuntu_docker.tar ubuntu_testimport
# 导入容器
docker [container] import ubuntu_docker.tar ubuntu_test_20.04
# import与load区别在于 前者导出完整数据的镜像 后者导出当前容器快照inspect
# 查看容器详情
docker container inspect ubuntu_testtop
# 查看容器内部进程
docker [container] top ubuntu_teststats
# 查看容器状态
docker [container] stats ubuntu_test
# 可选项
-a # 输出所有容器统计信息
-format string # 格式化输出信息
-no-stream # 不持续输出
-no-trunc # 不截断信息cp
# 复制文件
docker [container] cp filepath container:file_pathdiff
# 查看容器内文件系统变更
docker [container] dirr ubuntu_testport
# 查看端口映射
docker container port ubuntu_testupdate
# 更新运行时配置
docker [container] update
# 可选项docker volume
volume
ls
# 查看数据卷
docker volume lscreate
# 创建数据卷
docker volume create volume_nameinspect
# 查看卷详细信息
docker volume inspect volume_namerm
# 删除数据卷
docker volume rm volume_nameprune
# 清理所有无主数据卷
docker volume prunedocker tag
tag
# 为本地镜像添加新的标签
docker tag ubuntu:20.04 myubuntu:20.04docker history
history
# 查看镜像历史
docker history ubuntu:20.04docker search
search
# 搜索镜像
docker search [option] nginx # 搜索包含nginx关键词的仓库
## 可选项
-f # 过滤输出
--format string # 格式化输出
--limit int # 限制输出结果个数
--no-trunc # 不截断输出docker system
system
# 查看镜像、容器、数据卷所占用的空间
docker system df
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 总镜像数量 正在运行镜像数量 总镜像大小 可回收空间
# Containers 总容器数量 正在运行容器数量 总容器大小 可回收空间
# Local Volumes 总数据卷数量 正在运行数据卷数量 总数据卷大小 可回收空间
# Build Cache 总缓存数量 0 总缓存大小 可回收空间docker manifest
manifest
inspect
# 查看容器manifest表
docker manifest inspect imagecreate
# 将镜像推送至dockerhub后, 创建manifest列表
docker manifest create username/test \
username/test-x86-64 \
username/test-arm64annotate
# 设置manifest列表
docker manifest annotate username/test \
username/test-x86-64 \
--os linux --arch x86_64
docker manifest annotate username/test \
username/arm64v8-test \
--os linux --arch arm64 --variant v8push
# 推送manifest列表
docker manifest push username/testdocker network
network
ls
# 查看docker网络
docker network lscreate
# 新建docker网络, 可指定网络类型为bridge或overlay
docker network create -d bridge/overlay network_namedocker compose
compose
# compose格式
docker compose \
-f filepath \ # 指定compose模板文件, 默认docker-compose.yml
-p project_name \ # 指定项目名称, 默认以目录所在名作为项目名称
--verbose \ # 输出更多调试信息version
# 查看docker compose版本
docker compose versionbuild
# docker compose build构建服务
docker compose build \
--force-rm \ # 删除构建过程中的临时容器
--no-cache \ # 构建镜像过程不使用cache
--pull \ # 始终通过pull获取最新镜像config
# 检查配置是否正确
docker compose configdown
# 停止up启动容器, 并移除网络
docker compose downexec
# 进入指定容器
docker compose exechelp
# 获取帮助
docker compse helpimages
# 列出所有包含镜像
docker compose imageskill
# 发出信号停止服务容器
docker compose kill -s SIGINTlogs
# 查看容器输出
docker compose logspause
# 暂停容器
docker compose pauseport
# 打印容器端口映射的公共端口
docker compose port --protocol=tcp|udp \ # 指定端口协议
--ndex=index \ # 指定命令对象容器序号ps
# 列出项目中所有容器
docker compose pspull
# 拉取服务依赖镜像
docker compose pullpush
# 推送服务依赖镜像到Docker仓库
docker compose pushrestart
# 重启项目中的服务
docker compose restartrm
# 删除所有停止状态的服务容器
docker compose rmDockerHub
# 注册dockerhub账号
https://hub.docker.com
# 登录dockerhub
docker login -u dfwhy
dckr_pat_suyaZ_4ArOClsaMREX_m7RqCKS0
# 上传镜像
docker [image] push test_user/myubuntu:20.04
# 退出登录
docker logoutDockerfile
Dockerfile 编写规则
# 以某个镜像为基础进行修改, scratch为空白不存在镜像, 可使用as为某一阶段命名
FROM scratch as set_name
# 执行命令, 每次执行完指令后自动提交为一个commit, 所以最好删除所有无用文件
RUN shell_command
# 复制文件, 修改文件所属者
COPY --chown=user:group 上下文路径 目标路径
# 复制文件, 从其他镜像负责文件
COPY --from=image_name:tag 镜像中文件路径 目标路径
# 与COPY同, 貌似能自动解压, 懒得用
ADD 与COPY同
# 容器启动默认运行的进程, 该进程执行结束容器也会自动关闭
CMD [ "sh", "-c", "echo $HOME" ]
# 使用ENTRYPOINT后会将CMD的内容作为参数传给ENTRYPOINT, 可用来追加参数
ENTRYPOINT 与CMD同
# 定义环境变量, 容器运行时任有该环境变量
ENV $SHELL=/bin/bash
# 定义环境变量, 但容器运行时消失
ARG 与ENV同
# 挂载目录, 指定容器的/data自动转化为匿名卷
VOLUME /data
# 声明容器运行时提供服务端口
EXPOSE port1 port2
# 指定工作目录
WORKDIR 路径
# 指定当前用户
USER user:group
# 健康检查
HEALTHCHECK --interval=健康检查间隔 \
--timeout=健康检查运行超时时间 \
--retries=连续失败指定次数 \
# 当前镜像不调用接的命令, 继承镜像才调用
ONBUILD Docker Command
# 键值对形式添加元数据
LABEL <key>=<value>Docker yml编写规则
version: "3" # 指定版本
services: # 所有服务
webapp: # 服务名称
user: nginx # 容器运行应用的用户名
working_dir: /code # 工作目录
container_name: web-container # 指定服务名称
image: examples/web # 选择镜像
build:
context: ./webapp # 指定dockerfile所在文件夹路径
dockerfile: Dockerdile # 指定dockerfile文件名
args:
buildno: 1 # 构建变量过程中使用的参数
cache_from: # 指定构建镜像的缓存
- alpine:latest
- corp/web_app:3.14
command: echo "hello world" # 容器启动后默认执行命令, 覆盖RUN
devices: # 设备间映射关系
- "/dev/ttyUSB1:/dev/ttyUSB0"
ports: # 端口映射
- "80:80"
volumes: # 数据卷挂载路径
- "/data"
depends_on: # 容器间依赖关系, 会先等待redis和db启动后再启动, 但不会等待完全启动成功
- db
- redis
dns: 8.8.8.8 # 指定DNS服务器
tmpfs: # 挂载tmpfs文件系统到容器
- /run
- /tmp
environment: # 设置环境变量
- RACK_ENV=development
- SESSION_SECRET
extra_hosts: # 添加映射信息
- "googledns:8.8.8.8"
- "dockerhub:52.1.157.61"
healthcheck: # 进行健康检查
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
labels: # 添加元数据
com.startupteam.description: "webapp for a startup team"
com.startupteam.department: "devops department"
com.startupteam.release: "rc3 for v1.0"
network_mode: "bridge" # 设置网络模式
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
pid: "host" # 与主机系统共享进程命名空间
sysctls: # 配置容器内核参数
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
ulimits: # 指定容器限制值
nproc: 65535
nofile:
soft: 20000
hard: 40000
networks: # 配置容器连接网络
some-network:
other-network:Docker技术细节
Docker镜像层
Docker在容器中修改文件时, 实际上时将镜像层中的文件复制至容器层, 然后修改容器层中副本, 该方法称为写时复制, COW(copy-on-write)
# 查看docker存储驱动
docker info | grep -i "storage"
# Storage Driver: overlay2 Linux内核大于等于4.0时一般用overlayfs2overlay2 文件系统分层结构
![]()
- 最下层为"lower层", 其中数据为只读, "lower层"数量可以是多个
- 中间层为"upper层", 其中数据可读可写
- 最上层为"merged层", 即用户看到的叠加混合视图
# 测试overlay2
# 创建3个lower层, upper层和merged层, work为文件系统使用的临时工作目录, 在挂载中使用
mkdir -p overlay2_test/lower{1,2,3} overlay2_test/{work,upper,merged}
# 创建测试文件
echo "file1 -lower1" > overlay2_test/lower1/file1
echo "file2 -lower1" > overlay2_test/lower1/file2
echo "file2 -lower2" > overlay2_test/lower2/file2
echo "file3 -lower3" > overlay2_test/lower3/file3
mkdir -p overlay2_test/lower2/tdir
mkdir -p overlay2_test/lower3/tdir
echo "file1 - tdir -lower2" > overlay2_test/lower2/tdir/file1
echo "file2 - tdir -lower3" > overlay2_test/lower3/tdir/file2
# overlay2_test/
# ├── lower1
# │ ├── file1
# │ └── file2
# ├── lower2
# │ ├── file2
# │ └── tdir
# │ └── file1
# ├── lower3
# │ ├── file3
# │ └── tdir
# │ └── file2
# ├── merged
# ├── upper
# └── work
# 挂载文件系统
cd overlay2_test/
mount -t overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work overlay merged
# 文件系统结构为
# merged
# overlay
# lower1
# lower2
# lower3
# 测试是否挂载成功
mount | grep overlay | grep overlay2_test
# overlay on /root/overlay2_test/merged type overlay (rw,relatime,lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work,uuid=on,nouserxattr)
# overlay2_test/
# ├── lower1
# │ ├── file1
# │ └── file2
# ├── lower2
# │ ├── file2
# │ └── tdir
# │ └── file1
# ├── lower3
# │ ├── file3
# │ └── tdir
# │ └── file2
# ├── merged
# │ ├── file1
# │ ├── file2
# │ ├── file3
# │ └── tdir
# │ ├── file1
# │ └── file2
# ├── upper
# └── work
# └── work
# 进行测试
cat overlay2_test/merged/file1
# file1 -lower1
cat overlay2_test/merged/file2
# file2 -lower1
cat overlay2_test/merged/file3
# file3 -lower3
cat overlay2_test/merged/tdir/file1
# file1 - tdir -lower2
cat overlay2_test/merged/tdir/file2
# file2 - tdir -lower3
## 修改测试
echo "file1 - merged" > overlay2_test/merged/file1
cat overlay2_test/merged/file1
# file1 - merged
cat overlay2_test/lower1/file1
# file1 -lower1
# overlay2_test/
# ├── lower1
# │ ├── file1
# │ └── file2
# ├── lower2
# │ ├── file2
# │ └── tdir
# │ └── file1
# ├── lower3
# │ ├── file3
# │ └── tdir
# │ └── file2
# ├── merged
# │ ├── file1
# │ ├── file2
# │ ├── file3
# │ └── tdir
# │ ├── file1
# │ └── file2
# ├── upper
# │ └── file1
# └── work
# └── work
## 删除测试
rm overlay2_test/merged/file3
# overlay2_test/
# ├── lower1
# │ ├── file1
# │ └── file2
# ├── lower2
# │ ├── file2
# │ └── tdir
# │ └── file1
# ├── lower3
# │ ├── file3
# │ └── tdir
# │ └── file2
# ├── merged
# │ ├── file1
# │ ├── file2
# │ └── tdir
# │ ├── file1 -rw-r--r-- 1 root root 15 Oct 3 16:00 file1
# │ └── file2 c--------- 2 root root 0, 0 Oct 3 16:03 file3
# ├── upper
# │ ├── file1
# │ └── file3
# └── work
# └── work
# └── #11
# 删除操作实际上实在upper层创建一个without文件, 主次设备号均为0
## 手动删除测试
mknod overlay2_test/upper/tdir c 0 0
# overlay2_test/
# ├── lower1
# │ ├── file1
# │ └── file2
# ├── lower2
# │ ├── file2
# │ └── tdir
# │ └── file1
# ├── lower3
# │ ├── file3
# │ └── tdir
# │ └── file2
# ├── merged
# │ ├── file1
# │ └── file2
# ├── upper
# │ ├── file1
# │ ├── file3
# │ └── tdir
# └── work
# └── work
# └── #11Docker镜像的层存放在/var/lib/docker/overlay2/哈希值/diff
Docker在镜像层最上还增加了init层, /etc/hosts、/etc/hostname、/etc/resolv.conf文件均由Docker生成
Docker 踩坑
Docker动态修改端口号
# 查看该容器开放端口
docker port 容器ID
# 获取容器Id
docker inspect 容器ID | grep Id
# 停止容器
docker stop 容器ID
# 停止docker服务
systemctl stop docker
vim /var/lib/docker/containers/容器Id/hostconfig.json
# 在$PortBindings$中添加端口
"映射端口/tcp":[{"HostIp":"","HostPort":"暴露端口"}
vim /var/lib/docker/containers/容器Id/config.v2.json
# 在$ExposedPorts$中添加端口
“映射端口/tcp”:{}
# 启动docker服务
systemctl start docker 参考:
Docker — 从入门到实践