RHEL——Docker容器技术

Docker 是一款开源的容器化平台,通过将应用及其依赖打包成轻量级、可移植的镜像,实现一次构建,到处运行。相比传统虚拟机,Docker 容器共享宿主机内核,启动快、资源占用低,常用于开发环境统一、应用快速部署、微服务架构落地。


一、Docker 介绍

1. 什么是 Docker

Docker 是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术

特点

|---------|---------------------------------------------|
| 轻量级虚拟化 | Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源 |
| 一致性 | 确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现 |
| 可移植性 | 可轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差异 |
| 高效的资源利用 | 多个 Docker 容器可以共享主机的操作系统内核,从而更有效地利用系统资源 |
| 易于部署和扩展 | 能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展 |


2. Docker 应用场景

在企业中 docker 作为业务的最小载体而被广泛应用,通过 docker 企业可以更效率的部署应用并更节省资源

  • IaaS(Infrastructure as a Service):基础设施即服务
  • PaaS(Platform as a Service):平台即服务
  • SaaS(Software as a Service):软件运营服务

容器工作方式


3. Docker 与虚拟机区别

|------|------------------|-----------|
| | 虚拟机 | docker 容器 |
| 操作系统 | 宿主机上运行虚拟机 OS | 共享宿主机 OS |
| 存储 | 镜像较大(GB) | 镜像小(MB) |
| 性能 | 操作系统额外的 cpu、内存损耗 | 几乎无性能损耗 |
| 移植性 | 笨重、与虚拟化技术耦合度高 | 轻量、灵活迁移 |
| 隔离性 | 完全隔离 | 安全隔离 |
| 部署 | 慢,分钟级 | 块,秒级 |
| 运行密度 | 一般几十个 | 单机支持上千容器 |


二、部署 Docker

docker 站点:https://docs.docker.com/

1. 配置软件创库

docker 软件创库链接:https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/

利用阿里云部署软件仓库

复制代码
[root@docker-N1 ~]# cat > /etc/yum.repos.d/docker.repo << EOF
[docker]
name = docker
baseurl = https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
gpgcheck = 0
EOF
[root@docker-N1 ~]# dnf makecache

2. 安装 Docker

安装 docker-ce 并激活内核网络,然后启动 docker 服务

复制代码
[root@docker-N1 ~]# dnf install docker-ce -y
[root@docker-N1 ~]# vim /lib/systemd/system/docker.service
 15 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true
[root@docker-N1 ~]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
[root@docker-N1 ~]# modprobe -a br_netfilter
[root@docker-N1 ~]# cat > /etc/sysctl.d/docker.conf << EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
[root@docker-N1 ~]# sysctl --system
[root@docker-N1 ~]# systemctl enable --now docker.service

三、 Docker 基本操作

1. 配置 Docker 加速

因为 Docker Hub 在国外,国内直接访问非常慢,甚至连接不上,所以要配置 docker 加速

配置加速并重启 docker 服务

复制代码
[root@docker-N1 ~]# cat > /etc/docker/daemon.json << EOF
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.nju.edu.cn"
  ],
  "ipv6": false,
  "dns": ["223.5.5.5", "114.114.114.114"]
}
EOF
[root@docker-N1 ~]# systemctl restart docker.service
[root@docker-N1 ~]# docker info | grep -A 5 "Registry Mirrors"

2. 镜像管理

(1)搜索镜像

NAME 镜像名称,DESCRIPTION 镜像说明,STARS 点赞数量,OFFICIAL 是否是官方

复制代码
[root@docker-node1 ~]# docker search  nginx
NAME    DESCRIPTION                STARS         OFFICIAL
nginx   Official build of Nginx.   21206         [KO] 

(2)拉取镜像

有时候在搜索镜像因为网络问题搜不到镜像,但也是可以下载镜像的

下载镜像;可以不指定版本、指定版本和指定版本最小发型安装下载

复制代码
[root@docker-N1 ~]# docker pull busybox
[root@docker-N1 ~]# docker pull nginx:1.26
[root@docker-N1 ~]# docker pull nginx:1.26-alpine

(3)查看镜像

复制代码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker history busybox:latest
[root@docker-N1 ~]# docker image inspect nginx:1.26

(4)导出镜像

复制代码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker save -o nginx1.26-min.tar nginx:1.26
[root@docker-N1 ~]# docker save $(docker images --format "{{.Repository}}:{{.Tag}}") -o images.tar
[root@docker-N1 ~]# ls

(5)删除镜像

复制代码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker rmi nginx:1.26-alpine
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker rmi $(docker images -q)

(6)导入镜像

复制代码
[root@docker-N1 ~]# ls
[root@docker-N1 ~]# docker load -i nginx1.26-min.tar
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker load -i images.tar
[root@docker-N1 ~]# docker images

3. 容器操作

(1)运行容器

运行容器

  • -d 后台运行容器

  • -it 交互式运行容器(交互式运行容器退出默认停止容器)

    [root@docker-N1 ~]# docker run -d --name web nginx:1.26
    [root@docker-N1 ~]# docker run -it busybox:latest


(2)退出与进入容器

退出容器

  • 按"ctrl+d"退出并停止容器

  • 按"ctrl+p+q"退出不停止容器(后台运行)

    [root@docker-N1 ~]# docker run -it busybox:latest
    / # #按ctrl+d
    [root@docker-N1 ~]# docker ps -a
    [root@docker-N1 ~]# docker start romantic_fermi
    [root@docker-N1 ~]# docker attach romantic_fermi
    / # #按ctrl+p+q


(3)查看容器

复制代码
[root@docker-N1 ~]# docker ps
[root@docker-N1 ~]# docker ps -a

(4)停止与启动容器

复制代码
[root@docker-N1 ~]# docker ps
[root@docker-N1 ~]# docker stop web
[root@docker-N1 ~]# docker ps -a
[root@docker-N1 ~]# docker start web
[root@docker-N1 ~]# docker ps

(5)删除容器

只有已停止运行容器才能删除

  • kill 强制停止
  • stop 停止

"docker container prune -f"删除所有停止的容器

复制代码
[root@docker-N1 ~]# docker ps
[root@docker-N1 ~]# docker kill quizzical_almeida
[root@docker-N1 ~]# docker ps -a
[root@docker-N1 ~]# docker rm quizzical_almeida
[root@docker-N1 ~]# docker ps -a

(6)创建新进程

因为有些镜像使用 attach 进入容器后,无法用"ctrl+d"和"ctrl+p+q"来退出,只能用"ctrl+c"来退出,但是 attach 进入后是交互式运行,直接退出会导致容器停止。

所以需要创建子进程来对容器进行操作调试。

在用 attach 进入主进程,也不建议用"ctrl+d"(虽然无效),但如果有效会导致容器停止。

复制代码
[root@docker-N1 ~]# docker attach web
                                        #按ctrl+c退出
[root@docker-N1 ~]# docker start web
[root@docker-N1 ~]# docker exec -it web /bin/bash
root@279d2827edf7:/#                    #按ctrl+d退出
[root@docker-N1 ~]# docker ps
[root@docker-N1 ~]# docker exec -it web /bin/bash
root@279d2827edf7:/#                    #按ctrl+p+q退出
[root@docker-N1 ~]# docker ps

(7)在运行容器中执行命令

交互式和非交互式执行命令

复制代码
[root@docker-N1 ~]# docker exec web touch /root/haha
[root@docker-N1 ~]# docker exec web ls /root
[root@docker-N1 ~]# docker exec -it web /bin/bash
root@279d2827edf7:/# ls /root/
root@279d2827edf7:/# touch /root/hehe
root@279d2827edf7:/# ls /root/

(8)容器内容提交

容器删除问题

  • 默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件

  • 如果想永久保存,那么我们需要把动作提交,提交后会生成新的镜像

  • 当我们在运行新镜像后即可看到我们提交的内容

    [root@docker-N1 ~]# docker ps
    [root@docker-N1 ~]# docker stop web
    [root@docker-N1 ~]# docker container prune -f
    [root@docker-N1 ~]# docker run -d --name web nginx:1.26
    [root@docker-N1 ~]# docker exec web ls /root


提交内容,实现永久保存

复制代码
[root@docker-N1 ~]# docker exec -it web /bin/bash
root@c62c3a13ef6e:/# touch /root/haha
root@c62c3a13ef6e:/# ls /root/
                    #按ctrl+p+q退出
[root@docker-N1 ~]# docker commit -m "add haha" web nginx-haha
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker run -it --name test nginx-haha:latest
2026/03/24 09:30:25 [notice] 1#1: start worker process 23        #按ctrl+p+q退出
[root@docker-N1 ~]# docker exec test ls /root

(9)系统与容器的传输

复制代码
[root@docker-N1 ~]# docker exec test ls /root
[root@docker-N1 ~]# docker cp test:/root/haha /mnt
[root@docker-N1 ~]# ls /mnt/
[root@docker-N1 ~]# docker cp /etc/passwd test:/root
[root@docker-N1 ~]# docker exec test ls /root

(10)容器的外部网络访问

容器有自己的独立网络空间,外部无法访问,所以需要做端口映射

开启并设置端口映射后,通过浏览器访问主机ip进行测试

复制代码
[root@docker-N1 ~]# docker pull timinglee/mario
[root@docker-N1 ~]# docker history timinglee/mario
[root@docker-N1 ~]# docker run -d --name mario -p 80:8080 timinglee/mario:latest

四、Docker 镜像构建

1. Docker 镜像简介

(1)镜像架构

  • 共享宿主机的 kernel
  • base 镜像提供的是最小的 Linux 发行版
  • 同一 docker 主机支持运行多种 Linux 发行版
  • 采用分层结构的最大好处是:共享资源

(2)镜像运行原理

  • Copy-on-Write 可写容器层(Container 透明层)
  • 容器层以下所有镜像层都是只读的
  • docker 从上往下依次查找文件
  • 容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
  • 一个镜像最多127层

(3)镜像获取方式

  • 基本镜像通常由软件官方提供
  • 企业镜像可以用官方镜像+ Dockerfile 来生成
  • 系统关于镜像的获取动作有两种: docker pull 镜像地址、docker load --i 本地镜像包

2. 构建镜像

构建镜像(build)和内容提交(commit)很像,但是"docker commit"从运行的容器创建镜像,操作不透明且无法复现;而"docker build"通过 Dockerfile 文件构建镜像,过程透明、可版本控制、可重复执行。

(1)内容提交对照

内容提交的镜像查看提交历史,没有明确的指令操作,导致信息不透明

复制代码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker run -it --name test busybox:latest
/ #             #ctrl+p+q退出
[root@docker-N1 ~]# docker exec test touch /root/haha
[root@docker-N1 ~]# docker exec test ls /root
[root@docker-N1 ~]# docker commit -m "add haha" test busybox-test
[root@docker-N1 ~]# docker history busybox-test:latest
[root@docker-N1 ~]# docker history nginx:1.26

(2)构建镜像参数

|------------|---------------------------------------------------------------------------------------------------------------|
| FROM | - 指定 base 镜像 eg:FROM busybox:version |
| COPY | - 复制文件 eg:COPY file /file 或者 COPY ["file","/"] |
| MAINTAINER | - 指定作者信息,比如邮箱 eg:MAINTAINER user@example.com - 在最新版的 docker 中用 LABEL KEY="VALUE" 代替 |
| ADD | - 功能和 copy 相似,指定压缩文件或 url eg: ADD test.tar /mnt 或者 eg:ADD http://ip/test.tar /mnt |
| ENV | - 指定环境变量 eg:ENV FILENAME test |
| EXPOSE | - 暴漏容器端口 eg:EXPOSE 80 |
| VOLUME | - 申明数据卷,通常指数据挂载点 eg:VOLUME ["/var/www/html"] |
| WORKDIR | - 切换路径 eg:WORKDIR /mnt |
| RUN | - 在容器中运行的指令 eg: touch file |
| CMD | - 在启动容器时自动运行动作可以被覆盖 eg:CMD echo FILENAME 会调用 shell解析 eg:CMD \["/bin/sh","-c","echo FILENAME"] 不调用 shell 解析 |
| ENTRYPOINT | - 和 CMD 功能和用法类似,但动作不可被覆盖 |


(3)构建简单镜像

创建一个构建镜像的目录,然后创建一个必须名为"Dockerfile"的文件,通过编辑给文件定义镜像内容(FROM 和 COPY 参数)

  • FROM 参数:指定基础镜像

  • COPY 参数: 复制文件到镜像

    [root@docker-N1 ~]# mkdir docker
    [root@docker-N1 ~]# cd docker/
    [root@docker-N1 docker]# vim Dockerfile
    [root@docker-N1 docker]# echo timinglee > timinglee
    [root@docker-N1 docker]# cat timinglee
    [root@docker-N1 docker]# docker build -t timinglee:v1 .
    [root@docker-N1 docker]# docker images
    [root@docker-N1 docker]# docker history timinglee:v1


(4)使用镜像参数

LABEL 参数

  • 添加标签

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 COPY timinglee /root
    3 LABEL creater=lee
    [root@docker-N1 docker]# docker build -t timinglee:v2 .
    [root@docker-N1 docker]# docker history timinglee:v2


ADD 参数

  • 复制文件或目录

  • 与 COPY 参数相似,但 ADD 参数能解压,COPY 参数不能解压

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY timinglee /root
    4 ADD lee /root
    [root@docker-N1 docker]# echo lee > lee
    [root@docker-N1 docker]# docker build -t timinglee:v3 .
    [root@docker-N1 docker]# docker history timinglee:v3
    [root@docker-N1 docker]# docker run -it --name lee3 timinglee:v3
    / # ls /root

ADD 解压功能

复制代码
[root@docker-N1 ~]# vim docker/Dockerfile
  1 FROM busybox:latest
  2 LABEL creater=lee
  3 COPY bin.tar.gz /root
  4 ADD bin.tar.gz /mnt
[root@docker-N1 docker]# tar zcf bin.tar.gz /bin
[root@docker-N1 docker]# docker build -t timinglee:v4 .
[root@docker-N1 docker]# docker history timinglee:v4
[root@docker-N1 docker]# docker run -it --name lee4 timinglee:v4
/ # ls root/
/ # ls mnt/

ENV 参数

  • 设置环境变量

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/$NAME"]
    [root@docker-N1 docker]# docker build -t timinglee:v5 .
    [root@docker-N1 docker]# docker history timinglee:v5
    [root@docker-N1 docker]# docker run -it --name lee5 timinglee:v5
    / # ls /root/


EXPOSE 参数

  • 设置容器端口号

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/$NAME"]
    7 EXPOSE 8080
    [root@docker-N1 docker]# docker build -t timinglee:v6 .
    [root@docker-N1 docker]# docker history timinglee:v6


VOLUME 参数

  • 声明数据卷

  • 持久化存储功能:即使容器删除了,该数据卷(目录)的数据也不会删除

  • 数据共享功能:系统目录"/var/lib/docker/volumes/xxxx/_data"与容器目录"/mnt"的数据同步

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/$NAME"]
    7 EXPOSE 8080
    8 VOLUME "/mnt"
    [root@docker-N1 docker]# docker build -t timinglee:v7 .
    [root@docker-N1 docker]# docker history timinglee:v7
    [root@docker-N1 docker]# docker run -it --name lee7 timinglee:v7
    / # #ctrl+p+q退出
    [root@docker-N1 docker]# docker inspect lee7 | grep -i mounts -A10

数据共享(数据同步)

复制代码
[root@docker-N1 docker]# touch /var/lib/docker/volumes/2baf6037af43f39c9d41df795b9ae71530443f0b2313d30a380c19bddad7164a/_data/{1..5}.txt
[root@docker-N1 docker]# ls /var/lib/docker/volumes/2baf6037af43f39c9d41df795b9ae71530443f0b2313d30a380c19bddad7164a/_data/
[root@docker-N1 docker]# docker exec lee7 ls /mnt
[root@docker-N1 docker]# docker exec lee7 rm -rf /mnt/{3..5}.txt
[root@docker-N1 docker]# docker exec lee7 ls /mnt
[root@docker-N1 docker]# ls /var/lib/docker/volumes/2baf6037af43f39c9d41df795b9ae71530443f0b2313d30a380c19bddad7164a/_data/

持久化存储

  • 当容器启动后,会在系统自动生成的数据卷是匿名卷

  • 当容器删除后,第一个匿名卷不会消失,但容器重启后会再生成一个新匿名卷

  • 这会导致容器的数据消失,并未持久化

  • 所以需要在开启容器时就命名数据卷,保证重新启动容器时挂载是同一个卷

    #不指定数据卷导致数据丢失
    [root@docker-N1 docker]# docker kill lee7
    [root@docker-N1 docker]# docker rm lee7
    [root@docker-N1 docker]# docker run -it --name lee7 timinglee:v7
    / # ls /mnt/
    / # #ctrl+p+q退出
    [root@docker-N1 docker]# docker inspect lee7 | grep -i mounts -A10
    [root@docker-N1 docker]# ls /var/lib/docker/volumes/2baf6037af43f39c9d41df795b9ae71530443f0b2313d30a380c19bddad7164a/_data/

复制代码
#方法一:指定老匿名卷
[root@docker-N1 docker]# docker kill lee7
[root@docker-N1 docker]# docker rm lee7
[root@docker-N1 docker]# docker run -it --name lee7 -v /var/lib/docker/volumes/2baf6037af43f39c9d41df795b9ae71530443f0b2313d30a380c19bddad7164a/_data:/mnt timinglee:v7
/ # ls /mnt/
/ #                #ctrl+d退出并停止
[root@docker-N1 docker]# docker rm lee7
复制代码
#方法二:自定义数据卷
[root@docker-N1 docker]# docker run -it --name lee7 -v mydata:/mnt timinglee:v7
/ # touch /mnt/{a..e}.txt
/ #                #ctrl+d退出并停止
[root@docker-N1 docker]# docker rm lee7
[root@docker-N1 docker]# docker run -it --name lee7 -v mydata:/mnt timinglee:v7
/ # ls /mnt/
/ #                #ctrl+d退出并停止
[root@docker-N1 docker]# docker inspect lee7 | grep -i mounts -A10
[root@docker-N1 docker]# ls /var/lib/docker/volumes/mydata/_data

WORKDIR 参数

  • 指定进入容器时直接进入到指定路径

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/$NAME"]
    7 EXPOSE 8080
    8 VOLUME "/mnt"
    9 WORKDIR "/mnt"
    [root@docker-N1 docker]# docker history timinglee:v8
    [root@docker-N1 docker]# docker run -it --name lee8 --rm timinglee:v8


CMD

  • 容器启动时执行的默认命令

  • 命令会被覆盖

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/NAME"] 7 EXPOSE 8080 8 VOLUME "/mnt" 9 WORKDIR "/mnt" 10 CMD ["/bin/sh","-c","/bin/echo NAME"]
    [root@docker-N1 docker]# docker build -t timinglee:v9 .
    [root@docker-N1 docker]# docker history timinglee:v9
    [root@docker-N1 docker]# docker run -it --name lee9 --rm timinglee:v9
    [root@docker-N1 docker]# docker run -it --name lee9 --rm timinglee:v9 echo haha


ENTRYPOINT 参数

  • 容器启动时执行的固定命令

  • 命令不能被覆盖

    [root@docker-N1 ~]# vim docker/Dockerfile
    1 FROM busybox:latest
    2 LABEL creater=lee
    3 COPY bin.tar.gz /root
    4 ADD bin.tar.gz /mnt
    5 ENV NAME=timinglee
    6 RUN ["/bin/sh","-c","touch /root/NAME"] 7 EXPOSE 8080 8 VOLUME "/mnt" 9 WORKDIR "/mnt" 10 ENTRYPOINT ["/bin/sh","-c","/bin/echo NAME"]


(5)构建 centos 可用镜像

创建一个测试容器,该容器能实现下载功能,所以需要搭配仓库

仓库源:https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/

复制代码
[root@docker-N1 docker]# docker pull centos:7
[root@docker-N1 docker]# docker run -it --rm --name centos centos:7 /bin/bash
[root@f1d2c5f2f277 /]# cat /etc/centos-release
[root@f1d2c5f2f277 /]# yum install gcc -y
[root@f1d2c5f2f277 /]# exit            #ctrl+d退出
[root@docker-N1 docker]# vim Dockerfile
  1 FROM centos:7
  2 LABEL Creater=lee
  3 RUN ["/bin/bash","-c","rm -rf /etc/yum.repos.d/*"]
  4 COPY centos7.repo /etc/yum.repos.d/centos7.repo
[root@docker-N1 docker]# vim centos7.repo
  1 [centos7]
  2 name = centos7
  3 baseurl = https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/
  4 gpgcheck = 0
[root@docker-N1 docker]# docker build -t centos:7-repo .
[root@docker-N1 docker]# docker run -it --rm --name centos centos:7-repo /bin/bash
[root@59d53d54131c /]# cat /etc/yum.repos.d/centos7.repo
[root@5cc43b9ef067 /]# yum install gcc -y
[root@5cc43b9ef067 /]# exit            #ctrl+d退出

3. 镜像优化

在可使用镜像的同时,减少镜像的大小,可加快构建速度,提高安全性和可维护性。

(1)搭建 nginx 服务镜像

在自己的基础镜像上添加 nginx 服务,用于对比大小

nginx 链接:https://nginx.org/download/nginx-1.26.3.tar.gz

搭建 nginx 服务镜像

  • 构建镜像时,可加"--no-cache"参数,不使用缓存,强制重新构建镜像

    [root@docker-N1 ~]# wget https://nginx.org/download/nginx-1.26.3.tar.gz
    [root@docker-N1 ~]# cd docker/
    [root@docker-N1 docker]# cp ~/nginx-1.26.3.tar.gz .
    [root@docker-N1 docker]# ls
    [root@docker-N1 docker]# vim Dockerfile
    1 FROM centos:7
    2 ADD nginx-1.26.3.tar.gz /mnt
    3 WORKDIR /mnt/nginx-1.26.3
    4 RUN yum install -y gcc make prce-devel openssl-devel
    5 RUN sed -i 's/CFLAGS="CFLAGS -g"/#CFLAGS="CFLAGS -g"/g' auto/cc/gcc
    6 RUN ./configure --with-http_ssl_module --with-http_stub_status_module
    7 RUN make
    8 RUN make install
    9 EXPOSE 80
    10 VOLUME ["/usr/local/nginx/html"]
    11 CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
    [root@docker-N1 docker]# docker build --no-cache -t webserver:v1 .
    [root@docker-N1 docker]# docker images


测试搭建出的 nginx 服务镜像是否可用

复制代码
[root@docker-N1 docker]# docker run -d --rm --name web webserver:v1
[root@docker-N1 docker]# docker ps -a
[root@docker-N1 docker]# docker exec -it web /bin/bash
[root@0b85e6c39fb3 nginx-1.26.3]# echo "How are you?" > /usr/local/nginx/html/index.html
[root@0b85e6c39fb3 nginx-1.26.3]# hostname -I
[root@0b85e6c39fb3 nginx-1.26.3]# curl 172.17.0.2
[root@0b85e6c39fb3 nginx-1.26.3]# curl http://localhost
[root@0b85e6c39fb3 nginx-1.26.3]# exit
[root@docker-N1 docker]# docker inspect web | grep IPAddress
[root@docker-N1 docker]# curl 172.17.0.2
[root@docker-N1 docker]# docker stop web
[root@docker-N1 docker]# docker ps -a

综上,一般搭建出来的 nginx 服务镜像可用,但是镜像大小太大,不利于维护

所以需要减小镜像大小,方法有三个:

  • 减少镜像的层数
  • 清理镜像构建的中间产物
  • 选择最精简的基础镜像

(1)方法一:缩减镜像层

减少镜像的层数

  • 构建镜像的相同参数层数太多、编译安装完程序后的不需要的文件未删除,导致镜像太大;所以需要将层数简化,并将多余的源码和依赖文件删除

    [root@docker-N1 ~]# cd docker/
    [root@docker-N1 docker]# cat Dockerfile


减少层数和删除多余文件

复制代码
[root@docker-N1 docker]# vim Dockerfile
  1 FROM centos:7-repo
  2 ADD nginx-1.26.3.tar.gz /mnt
  3 WORKDIR /mnt/nginx-1.26.3
  4 RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.3 &&     yum clean all
  5 EXPOSE 80
  6 VOLUME ["/usr/local/nginx/html"]
  7 CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@docker-N1 docker]# docker build --no-cache -t webserver:v2 .
[root@docker-N1 docker]# docker images

测试镜像

复制代码
[root@docker-N1 docker]# docker run -d --rm --name web webserver:v2
[root@docker-N1 docker]# docker exec web hostname -I
[root@docker-N1 docker]# curl 172.17.0.2
[root@docker-N1 docker]# docker stop web

(2)方法二:多阶段构建

清理镜像构建的中间产物

  • 根据第一种缩减镜像层方法,镜像大小还是和官方镜像有很大差距;所以需要使用多阶段构建(即多个临时镜像),将最终需要的东西打包到最终镜像,减小镜像大小

    [root@docker-N1 docker]# vim Dockerfile
    1 FROM centos:7-repo AS n1
    2 ADD nginx-1.26.3.tar.gz /mnt
    3 WORKDIR /mnt/nginx-1.26.3
    4 RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="CFLAGS -g"/#CFLAGS="CFLAGS -g"/g' auto/cc/gcc & & ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.3 && yum clean all
    5
    6 FROM centos:7-repo
    7 COPY --from=n1 /usr/local/nginx /usr/local/nginx
    8 EXPOSE 80
    9 VOLUME ["/usr/local/nginx/html"]
    10 CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]


测试镜像

复制代码
[root@docker-N1 docker]# docker run -d --rm --name web webserver:v3
[root@docker-N1 docker]# docker exec web hostname -I
[root@docker-N1 docker]# curl 172.17.0.2
[root@docker-N1 docker]# docker stop web

(3)方法三:使用最精简镜像

选择最精简的基础镜像

  • 多阶段构建镜像方法已经与官方的基础镜像差距很小了,如果还需要比官方的基础镜像要小,则需要搭建最精简镜像

使用google提供的最精简镜像:https://github.com/GoogleContainerTools/distroless

下载链接:gcr.io/distroless/base

导入"debian11.tar.gz"压缩包,然后导入最小 linux 镜像"gcr.io/distroless/base-debian11:latest"

  • 提供一个最小化的 Linux 运行环境
  • 只包含应用程序运行所需的文件
  • 没有 shell、没有包管理器、没有多余工具

同时下载 nginx:1.23 版本的镜像,因为 debian11 能与 nginx1.23 版本兼容(最多 nginx1.24)

复制代码
[root@docker-N1 ~]# ls
[root@docker-N1 ~]# cp debian11.tar.gz docker/
[root@docker-N1 ~]# cd docker/
[root@docker-N1 docker]# ls
[root@docker-N1 docker]# docker load -i debian11.tar.gz
[root@docker-N1 docker]# docker pull nginx:1.23
[root@docker-N1 docker]# docker images

搭建最小 nginx 服务的镜像

复制代码
[root@docker-N1 docker]# vim Dockerfile
  1 FROM nginx:1.23 AS n1
  2 ARG TIME_ZONE
  3 RUN mkdir -p /opt/var/cache/nginx && \
  4     cp -a --parents /usr/lib/nginx /opt && \
  5     cp -a --parents /usr/share/nginx /opt && \
  6     cp -a --parents /var/log/nginx /opt && \
  7     cp -aL --parents /var/run /opt && \
  8     cp -a --parents /etc/nginx /opt && \
  9     cp -a --parents /etc/passwd /opt && \
 10     cp -a --parents /etc/group /opt && \
 11     cp -a --parents /usr/sbin/nginx /opt && \
 12     cp -a --parents /usr/sbin/nginx-debug /opt && \
 13     cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
 14     cp -a --parents /usr/lib/x86_64-linux-gnu/libpcre* /opt && \
 15     cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
 16     cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
 17     cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
 18     cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
 19     cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
 20     cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
 21     cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
 22     cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
 23
 24 FROM gcr.io/distroless/base-debian11
 25 COPY --from=n1 /opt /
 26 EXPOSE 80 443
 27 ENTRYPOINT ["nginx","-g","daemon off;"]
[root@docker-N1 docker]# docker build --no-cache -t webserver:v4 .
[root@docker-N1 docker]# docker images

测试镜像

复制代码
[root@docker-N1 docker]# docker run -d --rm --name web webserver:v4
[root@docker-N1 docker]# docker ps
[root@docker-N1 docker]# docker inspect web | grep IPAddress
[root@docker-N1 docker]# curl 172.17.0.2
[root@docker-N1 docker]# docker stop web

五、Docker 镜像仓库管理

因为没有 Docker 仓库时,镜像只能以文件形式(如 docker save 导出)手动拷贝到每台机器,效率低且无法统一管理版本。

所以需要 Docker 仓库作为中央存储,实现镜像的统一存储、版本管理和按需拉取。

1. Docker 仓库介绍

Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。

它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。

Docker 仓库可以分为公共仓库和私有仓库:

  • 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。
  • 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。

通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。


2. Docker Hub 公共仓库

(1)Docker Hub 简介

Docker Hub 官网:https://hub.docker.com/

Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务,是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。

  • 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、Web 服务器等众多应用 的镜像。
  • 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。
  • 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。
  • 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。
  • 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。

(2)准备新 Docker 主机

为了进行后面的容器实验,准备一台新主机(192.168.153.20)

复制代码
[root@docker-N1 ~]# scp /etc/yum.repos.d/docker.repo root@192.168.153.20:/etc/yum.repos.d/docker.repo
[root@docker-N1 ~]# scp /lib/systemd/system/docker.service root@192.168.153.20:/lib/systemd/system/docker.service
[root@docker-N1 ~]# scp /etc/modules-load.d/docker_mod.conf root@192.168.153.20:/etc/modules-load.d/docker_mod.conf
[root@docker-N1 ~]# scp /etc/sysctl.d/docker.conf root@192.168.153.20:/etc/sysctl.d/docker.conf

[root@docker-N2 ~]# dnf install docker-ce -y
[root@docker-N2 ~]# modprobe -a br_netfilter
[root@docker-N2 ~]# sysctl --system
[root@docker-N2 ~]# systemctl enable --now docker.service

(3)创建 Docker 仓库

开启加速,访问https://hub.docker.com/注册一个仓库账号,创建自己的 docker 仓库


(4)配置虚拟机 HTTP 代理(考虑)

配置虚拟机 http 代理前提是,如果在宿主机上开了 http 代理,虚拟机的网络依旧访问不了外部环境,则需要在虚拟机里配置 http 代理;如果宿主机上开了 http 代理,虚拟机的网络能访问外部环境,则不需要配置虚拟机 http 代理。

在宿主机上运行 HTTP 代理服务(例如企业内网代理、本地调试代理),且代理地址为 http://虚拟机网段:端口号

在宿主机 Windows 上查看虚拟机的网段


在虚拟机上配置 docker 的 http 代理

复制代码
[root@docker-N1 ~]# mkdir -p /etc/systemd/system/docker.service.d
[root@docker-N1 ~]# cat > /etc/systemd/system/docker.service.d/http-proxy.conf << EOF
[Service]
Environment="HTTP_PROXY=http://192.168.153.1:7897"
Environment="HTTPS_PROXY=http://192.168.153.1:7897"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
[root@docker-N1 ~]# systemctl daemon-reload
[root@docker-N1 ~]# systemctl restart docker.service
[root@docker-N1 ~]# docker login -u forget8
Password:            #输入密码

[root@docker-N2 ~]# mkdir -p /etc/systemd/system/docker.service.d
[root@docker-N2 ~]# cat > /etc/systemd/system/docker.service.d/http-proxy.conf << EOF
[Service]
Environment="HTTP_PROXY=http://192.168.153.1:7897"
Environment="HTTPS_PROXY=http://192.168.153.1:7897"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
[root@docker-N2 ~]# systemctl daemon-reload
[root@docker-N2 ~]# systemctl restart docker.service

(5)上转镜像

往 docker 仓库上上转镜像,使其他主机能通过仓库拉取镜像

复制代码
[root@docker-N1 ~]# docker login -u forget8
Password:            #输入密码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker tag webserver:v4 forget8/timinglee
[root@docker-N1 ~]# docker push forget8/timinglee

(6)拉取镜像

推送和拉取镜像都建立在能访问 docker 仓库基础上,在国内的主机上需要配置 http 代理

复制代码
[root@docker-N2 ~]# docker images
[root@docker-N2 ~]# docker pull forget8/webserver:v4
[root@docker-N2 ~]# docker images

3. Docker 仓库工作原理

仓库中的三个角色

  • index docker 索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。
  • registry docker 仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过 Index Auth service 的 Token 的方式进行认证。
  • Registry Client Docker充当 registry 客户端来维护推送和拉取,以及客户端的授权。

(1)pull 原理

镜像拉取步骤

  • 1.docker 客户端向 index 发送镜像拉去请求并完成与 index 的认证
  • 2.index 发送认证 token 和镜像位置给 docker client
  • 3.docker client 携带 token 和根据 index 指引的镜像位置取连接 registry
  • 4.Registry 会根据 client 持有的 token 跟 index 核实身份合法性
  • 5.index 确认此 token 合法性
  • 6.Registry 会根据 client 的请求传递镜像到客户端

(2)push 原理

镜像上传的步骤

  • 1.client向index发送上传请求并完成用户认证
  • 2.index会发方token给client来证明client的合法性
  • 3.client携带index提供的token连接Registry
  • 4.Registry向index合适token的合法性
  • 5.index证实token的合法性
  • 6.Registry开始接收客户端上传过来的镜像

4. 搭建 Docker 私有仓库

因为公共仓库(如 Docker Hub)的访问速度受网络环境影响,在镜像拉取和推送时可能存在延迟。

所以对于内网环境或需要快速分发镜像的场景,搭建私有仓库能实现高速稳定的内网传输。

(1)搭建 Registry 基础仓库

Registry 是 Docker 官方提供的私有仓库工具,能在内网快速搭建镜像存储和分发服务,避免依赖外网 Docker Hub。

Registry 地址:https://docs.docker.com/retired/

下载 registry 镜像

复制代码
[root@docker-N1 ~]# docker pull registry
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker history registry:latest

开启 registry 容器,向容器推送镜像

复制代码
[root@docker-N1 ~]# docker run -d -p 5000:5000 -v my_registry1:/var/lib/registry --restart=always --name registry registry:latest
[root@docker-N1 ~]# docker inspect registry | grep -i mounts -A10
[root@docker-N1 ~]# docker tag webserver:v4 192.168.153.10:5000/webserver:v4
[root@docker-N1 ~]# docker push 192.168.153.10:5000/webserver:v4
[root@docker-N1 ~]# docker info | grep -i registries -A10

配置非加密端口,并再次推送镜像,然后查看镜像是否上转成功

复制代码
[root@docker-N1 ~]# vim /etc/docker/daemon.json
  1 {
  2     "insecure-registries":["http://192.168.153.10:5000"]
  3 }
[root@docker-N1 ~]# systemctl restart docker.service
[root@docker-N1 ~]# docker ps
[root@docker-N1 ~]# docker push 192.168.153.10:5000/webserver:v4
[root@docker-N1 ~]# curl http://192.168.153.10:5000/v2/_catalog

在 n2 主机上配置非加密端口,然后拉取私有仓库的镜像

复制代码
[root@docker-N2 ~]# vim /etc/docker/daemon.json
  1 {
  2     "insecure-registries":["http://192.168.153.20:5000"]
  3 }
[root@docker-N2 ~]# systemctl restart docker.service
[root@docker-N2 ~]# docker pull 192.168.153.10:5000/webserver:v4
[root@docker-N2 ~]# docker images

(2)给 Registry 添加加密证书

因为 HTTP 协议以明文传输数据,镜像内容和登录密码在网络中完全暴露,所以任何能访问网络的人都能窃取或篡改传输中的镜像。

因此需要添加加密证书,将通信升级为 HTTPS,防止数据被窃听和篡改。

创建证书

复制代码
[root@docker-N1 ~]# mkdir /etc/docker/certs
[root@docker-N1 ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /etc/docker/certs/timinglee.org.key -addext "subjectAltName = DNS:reg.timinglee.org" -x509 -days 365 -out /etc/docker/certs/timinglee.org.crt
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:guangxi
Locality Name (eg, city) [Default City]:guilin
Organization Name (eg, company) [Default Company Ltd]:docker
Organizational Unit Name (eg, section) []:registry
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org
[root@docker-N1 ~]# openssl x509 -in /etc/docker/certs/timinglee.org.crt -noout -text

删除非加密端口配置,并开启容器 ,配置解析

  • 方案1:如果虚拟机之前因网络环境原因配置了 HTTP 代理,而在访问内网私有仓库时,需要将私有仓库地址添加到 no_proxy 环境变量中,避免代理干扰内网访问。

  • 方案2:私有仓库通常部署在内网,访问速度快且稳定,所以可以直接删除 http 代理配置

    [root@docker-N1 ~]# > /etc/docker/daemon.json
    [root@docker-N1 ~]# docker rm -f registry
    [root@docker-N1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /opt/registry:/var/lib/registry -v /etc/docker/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry
    [root@docker-N1 ~]# echo "192.168.153.10 reg.timinglee.org" >> /etc/hosts

    方案1:开启代理
    [root@docker-N1 ~]# vim /etc/systemd/system/docker.service.d/http-proxy.conf
    1 [Service]
    2 Environment="HTTP_PROXY=http://192.168.153.1:7897"
    3 Environment="HTTPS_PROXY=http://192.168.153.1:7897"
    4 Environment="NO_PROXY=localhost,127.0.0.1,reg.timinglee.org,192.168.153.10"

    方案2:关闭代理
    [root@docker-N1 ~]# > /etc/systemd/system/docker.service.d/http-proxy.conf


配置 Docker 公认证书

  • 因为我们自建的证书不是 Dokcer 公认的 ca 签发证书,所以推送镜像时导致 Docker 拒绝;因此我们需要拷贝自己的证书为 Docker 公认的 ca 证书

    [root@docker-N1 ~]# docker tag webserver:v4 reg.timinglee.org/webserver:v4
    [root@docker-N1 ~]# docker push reg.timinglee.org/webserver:v4
    [root@docker-N1 ~]# mkdir -p /etc/docker/certs.d/reg.timinglee.org/
    [root@docker-N1 ~]# cp /etc/docker/certs/timinglee.org.crt /etc/docker/certs.d/reg.timinglee.org/ca.crt
    [root@docker-N1 ~]# systemctl restart docker.service


再次推送镜像

复制代码
[root@docker-N1 ~]# docker push reg.timinglee.org/webserver:v4
[root@docker-N1 ~]# curl -k  https://reg.timinglee.org/v2/_catalog
[root@docker-N1 ~]# curl -k  https://192.168.153.10/v2/_catalog

测试 n2 主机拉取有加密证书后的镜像

  • 关闭代理、关闭非加密端口并添加解析,然后重启
  • 拷贝 ca 证书到 n2 主机上

错误信息 x509: certificate signed by unknown authority 明确表示:Docker 客户端不信任您的私有仓库的 SSL 证书。

复制代码
[root@docker-N2 ~]# > /etc/systemd/system/docker.service.d/http-proxy.conf
[root@docker-N2 ~]# > /etc/docker/daemon.json
[root@docker-N2 ~]# echo "192.168.153.10     reg.timinglee.org" >> /etc/hosts
[root@docker-N2 ~]# systemctl daemon-reload
[root@docker-N2 ~]# systemctl restart docker.service
[root@docker-N2 ~]# docker pull reg.timinglee.org/webserver:v4

[root@docker-N1 ~]# scp -r /etc/docker/certs.d/ root@192.168.153.20:/etc/docker/certs.d/

[root@docker-N2 ~]# docker pull reg.timinglee.org/webserver:v4
[root@docker-N2 ~]# docker images

(3)给 Registry 添加认证登录

因为 HTTPS 证书只负责加密传输通道,不验证操作者身份,所以任何知道仓库地址的人都能通过这个加密通道推送或拉取镜像。

因此需要额外添加用户登录,来确认只有授权的用户才能访问和修改仓库内容。

添加用户认证登录功能

复制代码
[root@docker-N1 ~]# docker rm -f registry
[root@docker-N1 ~]# dnf install httpd-tools -y
[root@docker-N1 ~]# mkdir /etc/docker/auth
[root@docker-N1 ~]# htpasswd -Bc /etc/docker/auth/htpasswd lee
New password:            #输入密码
Re-type new password:            #再次输入密码
[root@docker-N1 ~]# docker run -d -p 443:443 --restart=always --name registry -v /opt/registry:/var/lib/registry -v /etc/docker/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key -v /etc/docker/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry

测试 n1 主机登录推送

复制代码
[root@docker-N1 ~]# docker images
[root@docker-N1 ~]# docker tag busybox:latest reg.timinglee.org/busybox:latest
[root@docker-N1 ~]# docker push reg.timinglee.org/busybox:latest
[root@docker-N1 ~]# docker login reg.timinglee.org -u lee
Password:            #输入密码
[root@docker-N1 ~]# docker push reg.timinglee.org/busybox:latest
[root@docker-N1 ~]# curl -k -u lee:lee https://192.168.153.10/v2/_catalog

测试 n2 主机登录拉取

复制代码
[root@docker-N2 ~]# docker pull reg.timinglee.org/busybox:latest
[root@docker-N2 ~]# docker login reg.timinglee.org -u lee
Password:            #输入密码
[root@docker-N2 ~]# docker pull reg.timinglee.org/busybox:latest
[root@docker-N2 ~]# docker images

5. 构建企业级私有仓库

相关推荐
一个有温度的技术博主5 分钟前
网安实验系列七:域名收集
linux·运维·服务器
我爱学习好爱好爱9 分钟前
Ansible 环境搭建
linux·运维·ansible
yzx99101334 分钟前
实时数据流处理实战:从滑动窗口算法到Docker部署
算法·docker·容器
人工智能训练44 分钟前
从 1.1.3 到 1.13.2!Ubuntu 24.04 上 Dify 升级保姆级教程(零数据丢失 + 一键迁移)
linux·运维·人工智能·windows·ubuntu·dify
袖手蹲1 小时前
Arduino UNO Q 板载 Nanobot 自动化编程指南之七
运维·人工智能·自动化
我要成为嵌入式大佬1 小时前
正点原子MP157--问题详解--四(关于根文件系统驱动模块指令的注意事项)
linux·运维·服务器
feng68_1 小时前
Redis架构实践
linux·运维·redis·架构·bootstrap
欧云服务器1 小时前
宝塔计划任务怎么自动删除多少个以外的文件?
linux·运维·服务器
淼淼爱喝水1 小时前
openEuler 系统下 Ansible 一键安装教程(保姆级)
运维·ansible·openeuler
XXOOXRT1 小时前
零基础掌握Linux常用命令
linux·运维·服务器