Docker學習筆記(二):鏡像與容器管理

Docker

鏡像

最小的鏡像

hello-world 是 Docker 官方提供的一個鏡像,通常用來驗證 Docker 是否安裝成功。

先通過 docker pull 從 Docker Hub 下載它。

[root@docker ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
Digest: sha256:a0dfb02aac212703bfcb339d77d47ec32c8706ff250850ecc0e19c8737b18567
Status: Image is up to date for hello-world:latest
docker.io/library/hello-world:latest

用 docker images 命令查看鏡像的信息。

[root@docker ~]# docker images hello-world
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
hello-world   latest    1b44b5a3e06a   3 weeks ago   10.1kB

通過 docker run 運行。

[root@docker ~]# docker run hello-worldHello from Docker!
This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/

base鏡像

base 鏡像有兩層含義:

  • 不依賴其他鏡像,從 scratch 構建。

  • 其他鏡像可以之為基礎進行擴展。

所以,能稱作 base 鏡像的通常都是各種 Linux 發行版的 Docker 鏡像,比如 Ubuntu, Debian, CentOS 等。

在這里插入圖片描述

以 CentOS 為例考察 base 鏡像包含哪些內容。

下載鏡像:

docker pull centos:7

[root@docker ~]# docker pull centos:7
7: Pulling from library/centos
2d473b07cdd5: Pull complete
Digest: sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4
Status: Downloaded newer image for centos:7
docker.io/library/centos:7

查看鏡像信息:

[root@docker ~]# docker images centos:7
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
centos       7         eeb6ee3f44bd   3 years ago   204MB

Linux 操作系統由內核空間和用戶空間組成。如下圖所示:

在這里插入圖片描述

rootfs

內核空間是 kernel,Linux 剛啟動時會加載 bootfs 文件系統,之后 bootfs 會被卸載掉。

用戶空間的文件系統是 rootfs,包含我們熟悉的 /dev, /proc, /bin 等目錄。

對于 base 鏡像來說,底層直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。

而對于一個精簡的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序庫就可以了。相比其他 Linux 發行版,CentOS 的 rootfs 已經算臃腫的了,alpine 還不到 10MB。

我們平時安裝的 CentOS 除了 rootfs 還會選裝很多軟件、服務、圖形桌面等,需要好幾個 GB 就不足為 奇了。

base 鏡像提供的是最小安裝的 Linux 發行版。

支持運行多種 Linux OS

不同 Linux 發行版的區別主要就是 rootfs。

比如 Ubuntu 14.04 使用 upstart 管理服務,apt 管理軟件包;而 CentOS 7 使用 systemd 和 yum。這 些都是用戶空間上的區別,Linux kernel 差別不大。

所以 Docker 可以同時支持多種 Linux 鏡像,模擬出多種操作系統環境。

在這里插入圖片描述

上圖 Debian 和 BusyBox(一種嵌入式 Linux)上層提供各自的 rootfs,底層共用 Docker Host 的 kernel。

額外1
  • base 鏡像只是在用戶空間與發行版一致,kernel 版本與發型版是不同的。 例如 ubuntu使用 3.x.x 的 kernel,如果 Docker Host 是 CentOS Stream 8(比如我們的實驗環 境),那么在 CentOS 容器中使用的實際是是 Host 4.18.0 的 kernel。
[root@docker ~]# uname -r
4.18.0-553.6.1.el8.x86_64
#Host os kernel 為 4.18.0

啟動一個ubuntu,ubuntu內核正常與host os(centos stream 8)不一致

[root@docker ~]# docker run -it ubuntu
root@65a155bed367:/# uname -r
4.18.0-553.6.1.el8.x86_64

啟動一個centos:7,centos:7內核正常為3.10

[root@docker ~]# docker run -it centos:7
[root@1068e82c836b /]# uname -r
4.18.0-553.6.1.el8.x86_64
  • 容器只能使用 Host 的 kernel,并且不能修改。 所有容器都共用 host 的 kernel,在容器中沒辦法對 kernel 升級。如果容器對 kernel 版本有要求 (比如應用只能在某個 kernel 版本下運行),則不建議用容器,這種場景虛擬機可能更合適。
額外2
# 查看內核版本
[root@docker ~]# uname -r
4.18.0-553.6.1.el8.x86_64# 查看操作系統版本
[root@docker ~]# cat /etc/os-release
NAME="CentOS Stream"
VERSION="8"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Stream 8"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://centos.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_SUPPORT_PRODUCT_VERSION="CentOS Stream"

鏡像的分層結構

Docker 支持通過擴展現有鏡像,創建新的鏡像。

構建過程如下圖所示:

在這里插入圖片描述

可寫的容器層

當容器啟動時,一個新的可寫層被加載到鏡像的頂部。 這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。

所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。

在這里插入圖片描述

只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的。

對容器增刪改差操作如下:

操作具體執行
創建 文件新文件只能被添加在容器層中。
刪除 文件依據容器分層結構由上往下依次查找。找到后,在容器層中記錄該刪除操作。 具體實現 是,UnionFS會在容器層創建一個”whiteout”文件,將被刪除的文件“遮擋”起來。
修改 文件依據容器分層結構由上往下依次查找。找到后,將鏡像層中的數據復制到容器層進行修 改,修改后的數據保存在容器層中。(copy-on-write)
讀取 文件依據容器分層結構由上往下依次查找。

只有當需要修改時才復制一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化 的部分,不會對鏡像本身進行任何修改。

構建鏡像

Docker 提供了兩種構建鏡像的方法:
  • docker commit 命令

  • Dockerfile 構建文件

docker commit

docker commit 命令是創建新鏡像最直觀的方法,其過程包含三個步驟:

運行容器–修改容器 --將容器保存為新的鏡像

示例:

運行容器
[root@docker ~]# docker run -it ubuntu
root@dfcf8c139cb1:/#
安裝 vim

本身不帶vim

root@dfcf8c139cb1:/# vim
bash: vim: command not found
root@dfcf8c139cb1:/# apt-get update
Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]
Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Get:3 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages [1408 kB]
Get:4 http://archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:5 http://archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:6 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages [19.3 MB]
Get:7 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Packages [2159 kB]
Get:8 http://security.ubuntu.com/ubuntu noble-security/multiverse amd64 Packages [23.0 kB]
Get:9 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Packages [1135 kB]
Get:10 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages [1808 kB]
Get:11 http://archive.ubuntu.com/ubuntu noble/restricted amd64 Packages [117 kB]
Get:12 http://archive.ubuntu.com/ubuntu noble/multiverse amd64 Packages [331 kB]
Get:13 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1760 kB]
Get:14 http://archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Packages [2269 kB]
Get:15 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [1918 kB]
Get:16 http://archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Packages [45.2 kB]
Get:17 http://archive.ubuntu.com/ubuntu noble-backports/main amd64 Packages [48.8 kB]
Get:18 http://archive.ubuntu.com/ubuntu noble-backports/universe amd64 Packages [35.6 kB]
Fetched 33.0 MB in 37s (896 kB/s)
Reading package lists... Doneroot@dfcf8c139cb1:/# apt-get install -y vim
5
69
保存為新鏡像

一定要新開一個窗口查看!!!

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
dfcf8c139cb1   ubuntu    "/bin/bash"   3 minutes ago   Up 3 minutes             distracted_lehmann

dfcf8c139cb1 是新創建容器的ID

distracted_lehmann 是 Docker 為我們的容器隨機分配的名字。

將容器保存為鏡像
[root@docker ~]# docker commit distracted_lehmann ubuntu-with-vim
sha256:ba23f0e4a93f623c832ff90087f23979680e1b42e5c381b49978c29849ee9c04

新鏡像的命名為ubuntu-with-vim

查看新鏡像的屬性
[root@docker ~]# docker images
REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
ubuntu-with-vim   latest    ba23f0e4a93f   58 seconds ago   203MB
ubuntu            latest    802541663949   2 weeks ago      78.1MB
hello-world       latest    1b44b5a3e06a   3 weeks ago      10.1kB
httpd             latest    199e3a035264   3 weeks ago      117MB
centos            7         eeb6ee3f44bd   3 years ago      204MB
使用新鏡像
[root@docker ~]# docker run -it ubuntu-with-vim
root@03907d15a3e0:/# which vim
/usr/bin/vim
root@03907d15a3e0:/# vim file1
root@03907d15a3e0:/# cat file1
123

Dockerfile構建鏡像

Dockerfile 是一個文本文件,記錄了鏡像構建的所有步驟。

Dockerfile內容基礎知識:

  • 每條保留字指令都必須為大寫字母且后面要跟隨至少一個參數
  • 指令按照從上到下,順序執行
  • #表示注釋
  • 每條指令都會創建一個新的鏡像層并對鏡像進行提交

常用參數:

docker build -f [Dockerfile路徑] [構建上下文路徑]
參數作用
-f 或 --file標志符,聲明要使用自定義 Dockerfile
[Dockerfile路徑]絕對路徑或相對于構建上下文的路徑(如 subdir/Dockerfile.dev )
[構建上下文路徑]Docker 打包發送給守護進程的目錄(通常用 . 表示當前目錄)
第一個 Dockerfile

用 Dockerfile 創建上節的 ubuntu-with-vim

[root@docker ~]# cd /root/
[root@docker ~]# ls
anaconda-ks.cfg
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile .

在這里插入圖片描述

查看鏡像分層結構 ubuntu-with-vim-dockerfile 是通過在 base 鏡像的頂部添加一個新的鏡像層而得到的。

在這里插入圖片描述

[root@docker ~]# docker images
REPOSITORY                   TAG       IMAGE ID       CREATED              SIZE
ubuntu-with-vim-dockerfile   latest    e22fcd50ee9e   About a minute ago   203MB
ubuntu-with-vim              latest    ba23f0e4a93f   52 minutes ago       203MB
ubuntu                       latest    802541663949   2 weeks ago          78.1MB
hello-world                  latest    1b44b5a3e06a   3 weeks ago          10.1kB
httpd                        latest    199e3a035264   3 weeks ago          117MB
centos                       7         eeb6ee3f44bd   3 years ago          204MB[root@docker ~]# docker history ubuntu
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
802541663949   2 weeks ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:e67907c77897d2719…   78.1MB
<missing>      2 weeks ago   /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
<missing>      2 weeks ago   /bin/sh -c #(nop)  ARG RELEASE                  0B
[root@docker ~]# docker history ubuntu-with-vim-dockerfile:latest
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
e22fcd50ee9e   2 minutes ago   RUN /bin/sh -c apt-get update && apt-get ins…   125MB     buildkit.dockerfile.v0
<missing>      2 weeks ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 weeks ago     /bin/sh -c #(nop) ADD file:e67907c77897d2719…   78.1MB
<missing>      2 weeks ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 weeks ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 weeks ago     /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
<missing>      2 weeks ago     /bin/sh -c #(nop)  ARG RELEASE                  0B

鏡像的緩存特性

Docker 會緩存已有鏡像的鏡像層,構建新鏡像時,如果某鏡像層已經存在,就直接使用,無需重新創建。

示例1:

在前面的 Dockerfile 中添加一點新內容,往鏡像中復制一個文件:

[root@docker ~]# cd /root
[root@docker ~]# pwd
/root
[root@docker ~]# ls
anaconda-ks.cfg  Dockerfile
[root@docker ~]# touch testfile
[root@docker ~]# ls
anaconda-ks.cfg  Dockerfile  testfile
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
COPY testfile /
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile-2 .

在這里插入圖片描述

在 ubuntu-with-vi-dockerfile 鏡像上直接添加一層就得到了新的鏡像 ubuntu-with-vim-dockerfile-2。

在這里插入圖片描述

示例2:

如果我們改變 Dockerfile 指令的執行順序,或者修改或添加指令,都會使緩存失效。

交換前面 RUN 和 COPY 的順序:

[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
COPY testfile /
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile-3 .#雖然在邏輯上這種改動對鏡像的內容沒有影響,但由于分層的結構特性,Docker 必須重建受影響的鏡像層。

在這里插入圖片描述

上圖中看到[2/3],[3/3]都沒有使用緩存,最后生成了新的鏡像層,緩存已經失效。

調試Dockerfile

如果Dockerfile出現錯誤該如何解決?

示例:

先pull busybox

[root@docker ~]# ls
anaconda-ks.cfg  Dockerfile  testfile
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c "echo continue to build..."
COPY testfile /[root@docker ~]# docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
80bfbb8a41a2: Pull complete
Digest: sha256:ab33eacc8251e3807b85bb6dba570e4698c3998eca6f0fc2ccb60575a563ea74
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
[root@docker ~]# docker images
REPOSITORY                     TAG       IMAGE ID       CREATED          SIZE
ubuntu-with-vim-dockerfile-3   latest    f95f014aa80f   10 minutes ago   203MB
ubuntu-with-vim-dockerfile-2   latest    7de0cc8476dd   17 minutes ago   203MB
ubuntu-with-vim-dockerfile     latest    e22fcd50ee9e   2 hours ago      203MB
ubuntu-with-vim                latest    ba23f0e4a93f   3 hours ago      203MB
ubuntu                         latest    802541663949   2 weeks ago      78.1MB
hello-world                    latest    1b44b5a3e06a   3 weeks ago      10.1kB
httpd                          latest    199e3a035264   3 weeks ago      117MB
busybox                        latest    0ed463b26dae   11 months ago    4.43MB
centos                         7         eeb6ee3f44bd   3 years ago      204MB#基于剛才寫的Dockerfile構建鏡像image-debug
[root@docker ~]# docker build -t image-debug .

在這里插入圖片描述

Dockerfile 在執行第三步 RUN 指令時失敗。我們可以利用busybox的鏡像進行調試,方式是通過 docker run -it 啟動鏡像的一個容器。

在這里插入圖片描述

錯誤原因就是鏡像中沒有bash,busybox用的是sh,改錯就是把Dockerfile中的bash改成sh就可以了

在這里插入圖片描述

Dockerfile常用指令

FROM:鏡像構建的 “地基”

這是 Dockerfile 里必須放在第一行的指令,作用是指定一個基礎鏡像(base 鏡像)。后續所有指令都會基于這個基礎鏡像來疊加操作,相當于給鏡像構建找了個 “起點”。比如想基于 Ubuntu 系統構建鏡像,就可以寫FROM ubuntu:22.04(22.04 是具體的版本標簽,避免用 latest 以防版本變動)。

MAINTAINER:標注鏡像 “作者信息”

用來設置鏡像的作者,內容可以是任意字符串,比如個人姓名、郵箱,或者團隊名稱,主要作用是方便后續維護時識別鏡像歸屬。例如MAINTAINER Zhang San <zhangsan@example.com>,不過現在更推薦用LABEL maintainer="..."(LABEL 能承載更多元的元數據),但 MAINTAINER 作為傳統指令仍可使用。

COPY:簡單的 “文件復制工具”

功能是把 Docker 構建上下文(build context,也就是執行docker build時指定的目錄下的文件)里的文件或目錄,復制到鏡像內部的指定路徑。
它支持兩種寫法:

  • 簡潔版:COPY 源路徑 目標路徑(比如COPY app.jar /opt/
  • 數組版:COPY ["源路徑", "目標路徑"](當路徑包含空格或特殊字符時用,比如COPY ["my app", "/opt/my app"]
    關鍵注意點:源路徑只能是構建上下文里的文件 / 目錄,不能寫上下文之外的路徑(比如../file.txt這種上級目錄路徑是無效的)。
ADD:帶 “自動解壓” 的復制指令

和 COPY 的核心功能一致(從構建上下文復制到鏡像),但多了一個特殊能力:如果源文件是常見的歸檔格式(比如 tar、zip、tgz、xz 等),ADD 會自動把文件解壓到鏡像的目標路徑下,不用額外寫解壓命令。
比如ADD app.tar.gz /opt/,會直接把 app.tar.gz 里的所有文件解壓到 /opt/ 目錄下;但如果只是想單純復制歸檔文件(不想解壓),就用 COPY 更合適,避免 ADD 的 “自動解壓” 功能干擾。

ENV:給鏡像設置 “環境變量”

用來定義環境變量,這些變量不僅在構建鏡像時(后續的指令中)可以使用,容器運行時也能生效。
比如先定義ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk,之后的 RUN 指令就可以直接用這個變量:RUN echo $JAVA_HOME,容器啟動后也能通過echo $JAVA_HOME看到這個路徑,避免硬編碼路徑導致的維護麻煩。

EXPOSE:聲明容器 “監聽端口”

用來告訴 Docker,這個鏡像構建出的容器,內部進程會監聽某個或某些端口(比如 Web 服務監聽 80 端口)。
比如EXPOSE 80 443,表示容器內會監聽 80(HTTP)和 443(HTTPS)端口。
注意:EXPOSE 只是 “聲明”,不會自動把端口映射到主機;要實現主機和容器的端口映射,需要在docker run時用-p 主機端口:容器端口(比如-p 8080:80)來手動配置,這部分后續在容器網絡章節會詳細講。

VOLUME:聲明鏡像的 “數據卷”

把鏡像中的某個文件或目錄聲明為 “數據卷”(volume),數據卷的作用是讓容器的數據脫離容器本身存儲,方便數據持久化(比如數據庫的數據目錄),或者實現多個容器間共享數據。
比如VOLUME /var/lib/mysql,表示把容器內的 /var/lib/mysql 目錄(MySQL 的數據目錄)設為數據卷,后續容器運行時,這個目錄的數據會存在宿主機的指定位置,不會隨著容器刪除而丟失。具體的使用細節會在容器存儲章節展開。

WORKDIR:設置后續指令的 “工作目錄”

為 Dockerfile 中后面的 RUN、CMD、ENTRYPOINT、ADD、COPY 指令設置 “當前工作目錄”,相當于在鏡像內部切換到指定目錄,后續這些指令的操作都會基于這個目錄進行,不用每次都寫完整路徑。
比如先寫WORKDIR /opt/app,之后的COPY app.jar .就相當于COPY app.jar /opt/app/RUN java -jar app.jar也會在 /opt/app 目錄下執行,讓指令更簡潔。如果多次使用 WORKDIR,后續的指令會基于前一次的目錄疊加(比如先WORKDIR /opt,再WORKDIR app,最終工作目錄是 /opt/app)。

RUN:構建時 “執行命令”

鏡像構建過程中(也就是docker build的時候),在容器環境里執行指定的命令,執行結果會被保存到鏡像的分層中。
比如需要安裝軟件時,就用RUN apt update && apt install -y nginx(把多個命令用 && 連起來,減少鏡像分層);或者創建目錄RUN mkdir -p /opt/app。簡單說,RUN 是 “構建鏡像時要做的操作”。

CMD:容器 “啟動時執行的命令”

定義容器啟動時要運行的命令,比如啟動 Web 服務、數據庫服務等。
有幾個關鍵特性:

  • Dockerfile 里可以寫多個 CMD 指令,但只有最后一個會生效(前面的都會被覆蓋);
  • CMD 指定的命令可以被docker run后面的參數 “替換”。比如 Dockerfile 里寫CMD ["nginx", "-g", "daemon off;"],如果執行docker run 鏡像名 /bin/bash,就會用/bin/bash替換原來的 CMD 命令,容器啟動后會進入 bash 交互環境,而不是啟動 nginx。
ENTRYPOINT:容器 “固定啟動命令”

和 CMD 類似,也是設置容器啟動時運行的命令,但它的核心特點是 “不可被輕易替換”,更適合作為容器的 “固定入口程序”。
關鍵特性:

  • 同樣支持多個指令,但只有最后一個生效
  • CMD 的內容,或者docker run后面跟的參數,會被當作 “參數” 傳遞給 ENTRYPOINT 指定的命令。比如 Dockerfile 里寫ENTRYPOINT ["echo", "Hello"],再寫CMD ["World"],容器啟動后會執行echo Hello World;如果執行docker run 鏡像名 Docker,就會執行echo Hello Docker(用 “Docker” 替換了 CMD 的 “World” 作為參數)。
    簡單說,ENTRYPOINT 定義 “要做什么”,CMD 或docker run參數定義 “做這件事的參數”,適合需要固定核心程序、靈活調整參數的場景(比如工具類鏡像)。
綜合示例:
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
# my dockerfile
FROM busybox     				#從bustbox開始創建
MAINTAINER 123456@qq.com		#聲明作者信息
WORKDIR /testdir				#設置工作目錄
RUN touch tmpfile1				#在新鏡像中創建
COPY ["tmpfile2","."]			#將Dockerfile文件所在目錄中的tmpfile2文件拷貝到新鏡像中
ADD ["passwd.tar.gz","."]		#將Dockerfile文件所在目錄中的passwd.tar.gz文件拷貝到新鏡像中并壓縮
ENV WELCOME "You are in my container,welcome! hahahahaha"					  #設置環境變量WELCOME# 構建鏡像:# tmpfile2 用touch命令產生
[root@docker ~]# touch tmpfile2# passwd.tar.gz 用tar命令產生
[root@docker ~]# cp /etc/passwd .
[root@docker ~]# tar -cvzf passwd.tar.gz passwd
passwd
[root@docker ~]# pwd
/root
[root@docker ~]# rm passwd
[root@docker ~]# ls
anaconda-ks.cfg  Dockerfile  passwd.tar.gz  testfile  tmpfile2#構建新鏡像my-image
[root@docker ~]# docker build -t my-image .

驗證:

[root@docker ~]# docker run -it my-image
/testdir # pwd
/testdir
/testdir # ls
passwd    tmpfile1  tmpfile2
/testdir # echo $WELCOME
You are in my container,welcome! hahahahaha# 進入容器,當前目錄即為 WORKDIR
# WORKDIR 中保存了我們希望的文件和目錄
# ENV 指令定義的環境變量已經生效

RUN vs CMD vs ENTRYPOINT

Shell 格式
<instruction> <command>

例如

RUN apt-get install python3  
CMD echo "Hello world"  
ENTRYPOINT echo "Hello world" 

當指令執行時,shell 格式底層會調用 /bin/sh -c 。

示例:

[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
ENV name gqd
ENTRYPOINT echo "Hello, $name"[root@docker ~]# docker build -t dockerfile1 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 97B                                                  0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:3dc1f7ae4dd8e013ea883e40fd6af1eec21184e015ebfc68a83e00b  0.0s=> => naming to docker.io/library/dockerfile1                                       0.0s
[root@docker ~]# docker run dockerfile1
Hello, gqd# 環境變量 name 已經被值 gqd 替換。
Exec 格式
<instruction> ["executable", "param1", "param2", ...]

例如

RUN ["apt-get", "install", "python3"]  
CMD ["/bin/echo", "Hello world"]  
ENTRYPOINT ["/bin/echo", "Hello world"]

示例

[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
ENV name yuxb
ENTRYPOINT ["/bin/echo", "Hello, $name"][root@docker ~]# docker build -t dockerfile2 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 107B                                                 0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:d5d961b3b298e94273bcf4f50b903d2403549027d7baa757db3c6b7  0.0s=> => naming to docker.io/library/dockerfile2                                       0.0s
[root@docker ~]# docker run dockerfile2
Hello, $name# 環境變量“name”沒有被替換。

如果想替換,如下:

FROM busybox
ENV name yuxb  
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
ENV name yuxb
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"][root@docker ~]# docker build -t dockerfile3 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 116B                                                 0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:cb5385aa427e4ce20cf11448cc7710404040b99cc45f8a7112ac5cc  0.0s=> => naming to docker.io/library/dockerfile3                                       0.0s
[root@docker ~]# docker run dockerfile3
Hello, yuxb
小結

CMD 和 ENTRYPOINT 推薦使用 Exec 格式,因為指令可讀性更強,更容易理解。RUN 則兩種格式都可 以。

RUN

RUN 指令通常用于安裝應用和軟件包。

RUN 在當前鏡像的頂部執行命令,并通過創建新的鏡像層。Dockerfile 中常常包含多個 RUN 指令。

RUN 有兩種格式:

  • Shell 格式:RUN

  • Exec 格式:RUN [“executable”, “param1”, “param2”]

示例:

使用 RUN 安裝多個包

FROM ubuntu
RUN apt-get update && apt-get install -y bzr cvs git mercurial subversion
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y bzr cvs git mercurial subversion
[root@docker ~]# docker build -t dockerfile4 .
[+] Building 236.5s (6/6) FINISHED                                         docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 123B                                                 0.0s=> [internal] load metadata for docker.io/library/ubuntu:latest                     0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/2] FROM docker.io/library/ubuntu:latest                                0.0s=> [2/2] RUN apt-get update && apt-get install -y bzr cvs git mercurial subversi  235.3s=> exporting to image                                                               1.2s=> => exporting layers                                                              1.1s=> => writing image sha256:f5d2b0a3ad23038c70cc1a18294f558c9bd74ae1a3bccb995a27946  0.0s=> => naming to docker.io/library/dockerfile4                                       0.0s

驗證

[root@docker ~]# docker run -it dockerfile4
root@d3cd686296e4:/# apt list install brz cvs git mercurial subversion
Listing... Done
brz/noble,now 3.3.5-6build2 amd64 [installed,automatic]
cvs/noble,now 2:1.12.13+real-30build1 amd64 [installed]
git/noble-updates,noble-security,now 1:2.43.0-1ubuntu7.3 amd64 [installed]
mercurial/noble-updates,now 6.7.2-1ubuntu2.2 amd64 [installed]
subversion/noble,now 1.14.3-1build4 amd64 [installed]
root@d3cd686296e4:/#
CMD

CMD 指令允許用戶指定容器的默認執行的命令。

此命令會在容器啟動且 docker run 沒有指定其他命令時運行。

  • 如果 docker run 指定了其他命令,CMD 指定的默認命令將被忽略。

  • 如果 Dockerfile 中有多個 CMD 指令,只有最后一個 CMD 有效。

CMD 有三種格式:

  • Exec 格式:CMD [“executable”,“param1”,“param2”] 這是 CMD 的推薦格式。

  • CMD [“param1”,“param2”] 為 ENTRYPOINT 提供額外的參數,此時 ENTRYPOINT 必須使用 Exec 格式。

  • Shell 格式:CMD command param1 param2

第二種格式 CMD [“param1”,“param2”] 要與 Exec 格式 的 ENTRYPOINT 指令配合使用,其用途是為 ENTRYPOINT 設置默認的參數。在后面討論 ENTRYPOINT 時舉例說明。

下面看看 CMD 是如何工作的。Dockerfile 如下:

FROM busybox
CMD echo "Hello,world"
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
CMD echo "Hello,world"
[root@docker ~]# docker build -t dockerfile5 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 73B                                                  0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:e43571cba5b2433e067af8e01a3c850a4f93219a89b25744643c8a3  0.0s=> => naming to docker.io/library/dockerfile5                                       0.0s
[root@docker ~]# docker run -it dockerfile5
Hello,world[root@docker ~]# docker run -it dockerfile5 echo 666
666
[root@docker ~]# docker run -it dockerfile5 /bin/sh
/ #
ENTRYPOINT

ENTRYPOINT 指令的核心作用是讓容器能以應用程序或服務的形式運行,它和 CMD 有相似之處 —— 都能指定要執行的命令及參數,但兩者的關鍵區別在于:ENTRYPOINT 指定的命令不會被忽略,無論運行docker run時是否額外指定了其他命令,它都會被執行。

ENTRYPOINT 有兩種使用格式,選擇時要特別注意,因為不同格式的實際效果差異很大:

  1. Exec 格式(推薦)
    寫法是ENTRYPOINT ["可執行文件", "參數1", "參數2"],比如ENTRYPOINT ["nginx", "-g", "daemon off;"]。這種格式會直接調用指定的可執行文件,能夠正確接收后續的參數(包括 CMD 里的參數或docker run時附加的參數)。
  2. Shell 格式
    寫法是ENTRYPOINT 命令 參數1 參數2,比如ENTRYPOINT nginx -g "daemon off;"。這種格式會在 shell 中執行命令,此時docker run附加的參數無法傳遞給 ENTRYPOINT,實際使用中靈活性較低,不如 Exec 格式常用。
Exec 格式

ENTRYPOINT 的 Exec 格式用于設置要執行的命令及其參數,同時可通過 CMD 提供額外的參數。

ENTRYPOINT 中的參數始終會被使用,而 CMD 的額外參數可以在容器啟動時動態替換掉。

示例Dockerfile

FROM busybox
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
[root@docker ~]# docker build -t dockerfile6 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 98B                                                  0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:066e84f20225466825115eda2b0a68331ddb8d7d628844f37994c1a  0.0s=> => naming to docker.io/library/dockerfile6                                       0.0s
[root@docker ~]# docker run -it dockerfile6
Hello world[root@docker ~]# docker run -it dockerfile6 666
Hello 666
Shell 格式

ENTRYPOINT 的 Shell 格式會忽略任何 CMD 或 docker run 提供的參數。

示例Dockerfile

FROM busybox
ENTRYPOINT echo "Hello,"
CMD ["world"]
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM busybox
ENTRYPOINT echo "Hello,"
CMD ["world"][root@docker ~]# docker build -t dockerfile7 .
[+] Building 0.1s (5/5) FINISHED                                           docker:default=> [internal] load build definition from Dockerfile                                 0.0s=> => transferring dockerfile: 89B                                                  0.0s=> [internal] load metadata for docker.io/library/busybox:latest                    0.0s=> [internal] load .dockerignore                                                    0.0s=> => transferring context: 2B                                                      0.0s=> CACHED [1/1] FROM docker.io/library/busybox:latest                               0.0s=> exporting to image                                                               0.0s=> => exporting layers                                                              0.0s=> => writing image sha256:452cb29c2d513ff74ac8744c4c99a9e521c2da78edeee10829035e9  0.0s=> => naming to docker.io/library/dockerfile7                                       0.0s
[root@docker ~]# docker run -it dockerfile7
Hello,[root@docker ~]# docker run -it dockerfile7 666
Hello,
最佳實踐
  • 使用 RUN 指令安裝應用和軟件包,構建鏡像。

  • 如果 Docker 鏡像的用途是運行應用程序或服務,比如運行一個 MySQL,應該優先使用 Exec 格式 的 ENTRYPOINT 指令。CMD 可為 ENTRYPOINT 提供額外的默認參數,同時可利用 docker run 命 令行替換默認參數。

  • 如果想為容器設置默認的啟動命令,可使用 CMD 指令。用戶可在 docker run 命令行中替換此默認 命令。

Dockerfile案例:配置SSH鏡像

先創建Dockerfile

[root@docker ~]# vim centos.ssh.dockerfile
[root@docker ~]# cat centos.ssh.dockerfile
FROM centos:8.4.2105
MAINTAINER yuxb
RUN minorver=8.4.2105 && \
sed -e "s|^mirrorlist=|#mirrorlist=|g" \
-e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors                                                                                                                    .aliyun.com/centos-vault/$minorver|g" \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo
RUN yum install -y openssh-server
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN echo "root:123" | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]

構建鏡像

[root@docker ~]# docker build -t centos:ssh -f centos.ssh.dockerfile .# docker build:Docker 的構建命令,用于根據 Dockerfile 構建鏡像
# -t centos:ssh:指定構建出的鏡像的標簽(tag),格式為名稱:標簽,這里表示鏡像名為centos,標簽為ssh
# -f centos.ssh.dockerfile:指定要使用的 Dockerfile 文件名為centos.ssh.dockerfile(默認情況下會尋找名為Dockerfile的文件,這里用-f參數指定了自定義文件名)
# .:表示構建上下文的路徑為當前目錄,Docker 會將該目錄下的文件發送給 Docker 引擎用于構建鏡像

在這里插入圖片描述

查看現象

# docker history centos:ssh 這條命令的作用是查看 centos:ssh 這個 Docker 鏡像的構建歷史,即該鏡像是由哪些步驟(層)組成的。
[root@docker ~]# docker history centos:ssh
IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
0572296974cc   About a minute ago   CMD ["/usr/sbin/sshd" "-D"]                     0B        buildkit.dockerfile.v0
<missing>      About a minute ago   EXPOSE map[22/tcp:{}]                           0B        buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c echo "root:123" | chpasswd # …   1.77kB    buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c ssh-keygen -t ecdsa -f /etc/s…   695B      buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c ssh-keygen -t rsa -f /etc/ssh…   3.18kB    buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c yum install -y openssh-server…   51.9MB    buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c minorver=8.4.2105 && sed -e "…   17.6kB    buildkit.dockerfile.v0
<missing>      About a minute ago   MAINTAINER yuxb                                 0B        buildkit.dockerfile.v0
<missing>      3 years ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B    
<missing>      3 years ago          /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B    
<missing>      3 years ago          /bin/sh -c #(nop) ADD file:805cb5e15fb6e0bb0…   231MB 

測試

#基于剛才dockerfile創建的鏡像centos:ssh創建容器sshtest
[root@docker ~]# docker run -d -p 2022:22 --name sshtest centos:ssh
8f20df0046a8aecddd618265261b4d0db17f2e6f4f3605d5e1ef247b36b7518d
# -p 2022:22:端口映射,將容器內部的 22 端口(SSH 默認端口)映射到主機的 2022 端口。這意味著可以通過主機的 2022 端口訪問容器內的 SSH 服務
# --name sshtest:為容器指定一個名稱 sshtest,方便后續通過名稱管理容器(如停止、刪除等操作)
# centos:ssh:指定使用的鏡像,即之前構建的帶有 SSH 服務的 CentOS 鏡像#查看創建出來的容器
[root@docker ~]# docker ps
CONTAINER ID   IMAGE        COMMAND               CREATED          STATUS          PORTS                                   NAMES
8f20df0046a8   centos:ssh   "/usr/sbin/sshd -D"   14 seconds ago   Up 13 seconds   0.0.0.0:2022->22/tcp, :::2022->22/tcp   sshtest# ssh登錄容器測試ssh,能夠成功登錄
# 通過 SSH 協議 連接到容器內部。
[root@docker ~]# ssh root@localhost -p 2022# 第二種登陸方法
# 通過 Docker 自身的 exec 命令 直接進入容器內部的交互終端。
[root@docker ~]# docker exec -it sshtest bash

在這里插入圖片描述

在這里插入圖片描述

ssh直連192.168.108.30,端口號輸入2022也可以登錄

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95402.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95402.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95402.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STM32F103C8T6開發板入門學習——寄存器和庫函數介紹

學習目標&#xff1a;STM32F103C8T6開發板入門學習——寄存器和庫函數介紹學習內容&#xff1a; 1. 寄存器介紹 1.1 存儲器映射 存儲器本身無固有地址&#xff0c;是具有特定功能的內存單元。它的地址是由芯片廠商或用戶分配&#xff0c;給存儲器分配地址的過程就叫做存儲區映射…

【CouponHub項目開發】使用RocketMQ5.x實現延時修改優惠券狀態,并通過使用模板方法模式重構消息隊列發送功能

在上個章節中我實現了創建優惠券模板的功能&#xff0c;但是&#xff0c;優惠券總會有過期時間&#xff0c;我們怎么去解決到期自動修改優惠券狀態這樣一個功能呢&#xff1f;我們可以使用RocketMQ5.x新出的任意定時發送消息功能來解決。 初始方案&#xff1a;首先在創建優惠券…

Claude Code SDK 配置Gitlab MCP服務

一、MCP配置前期準備 &#xff08;一&#xff09;創建個人令牌/群組令牌 我這里是創建個人令牌&#xff0c;去到首頁左上角&#xff0c;點擊頭像——>偏好設置——>訪問令牌——>添加新令牌 &#xff08;二&#xff09;配置mcp信息 去到魔塔社區&#xff0c;點擊mc…

Eclipse 常用搜索功能匯總

Eclipse 常用搜索功能匯總 Eclipse 提供了多種搜索功能&#xff0c;幫助開發者快速定位代碼、文件、類、方法、API 等資源。以下是詳細的使用方法和技巧。 一、常用搜索快捷鍵快捷鍵功能描述Ctrl H打開全局搜索對話框&#xff0c;支持文件、Java 代碼、任務等多種搜索。Ctrl …

關于Spring的一些理解

Spring整體結構&#xff1a;Spring實際運行場景&#xff1a;基礎 Spring啟動過程 傳統Spring&#xff1a; &#xff08;1&#xff09;初始化準備階段 &#xff08;2&#xff09;容器創建與注入 &#xff08;3&#xff09;Bean工廠后置處理 &#xff08;4&#xff09;Bean工廠后…

Windows右下角系統托盤圖標快速顯示或隱藏

系統托盤指的是Windows電腦桌面右下角的區域&#xff0c;包括時間、wifi&#xff08;網絡&#xff09;、音量、電源、輸入法、一些程序/應用等。啟動了應用后&#xff0c;Windows會把部分應用的圖標顯示或隱藏在系統托盤區。我們可以根據需要快速顯示或隱藏相關應用&#xff0c…

Kotlin編程學習記錄2

Kotlin編程學習記錄2——條件與循環 條件語句&#xff1a;if 與 when ? Kotlin 的控制流把“表達式優先”作為設計原則——if、when 不只是控制語句&#xff0c;都可以作為表達式使用并返回值&#xff0c;這影響了日常代碼風格&#xff08;更函數式、可組合&#xff09;。筆…

印度物聯網崛起:政策紅利下的千億藍海與本土化博弈

印度物聯網市場正處于快速發展階段,2025年市場規模預計達到200億美元,主要得益于政府"數字印度"計劃和智能城市項目的推動。蜂窩物聯網連接數在2024年同比增長34%,2025年Q1增速進一步提升至32%,其中智能電表部署和資產追蹤應用成為核心驅動力。然而,市場也面臨著…

html學習:

ok,今天準備學一下html&#xff0c;花費點時間整理一下&#xff1a; HTML標簽的語法格式 HTML 中的標簽就像關鍵字一樣&#xff0c;每個標簽都有自己的語義&#xff08;含義&#xff09;。 HTML 標簽的語法格式 屬性↓ <div class"begin">cyx</div>↑…

CRYPT32!PkiAsn1Decode函數分析的一個例子

第一部分&#xff1a; 0: kd> g Breakpoint 35 hit CRYPT32!PkiAsn1Decode: 001b:75c9af0c 55 push ebp 1: kd> kc# 00 CRYPT32!PkiAsn1Decode 01 CRYPT32!PkiAsn1DecodeAndAllocInfo 02 CRYPT32!PkiAsn1DecodeAndAllocInfoEx 03 CRYPT32!Asn1InfoDecode…

大模型蒸餾、大模型微調、RAG

前言&#xff1a; 有很多同學想學習大模型開發&#xff0c;又無從下手&#xff0c;網上一搜&#xff0c;鋪天蓋地的付費課程。又不想當韭菜&#xff0c;打破認知障礙&#xff0c;通過自學&#xff0c;改變自己&#xff0c;改變世界&#xff01; 一、大模型蒸餾、微調、RAG的適…

25高教社杯數模國賽【E題保姆級思路+問題分析】

注&#xff1a;本內容由”數模加油站“ 原創出品&#xff0c;雖無償分享&#xff0c;但創作不易。 歡迎參考teach&#xff0c;但請勿抄襲、盜賣或商用。 E 題 AI輔助智能體測 《國家學生體質健康標準》的頒布&#xff0c;有效地促進了大中小學生關注自身體質健康的發展&#xf…

基于單片機車內換氣溫度檢測空氣質量檢測系統Proteus仿真(含全部資料)

全套資料包含&#xff1a;Proteus仿真源文件keil C語言源程序AD原理圖流程圖元器件清單說明書等 資料下載&#xff1a; 通過網盤分享的文件&#xff1a;資料分享 鏈接: 百度網盤 請輸入提取碼 提取碼: tgnu 目錄 資料下載&#xff1a; Proteus仿真功能 項目文件資料&#…

MySQL子查詢的分類講解與實戰

精選專欄鏈接 &#x1f517; MySQL技術筆記專欄Redis技術筆記專欄大模型搭建專欄Python學習筆記專欄深度學習算法專欄 歡迎訂閱&#xff0c;點贊&#xff0b;關注&#xff0c;每日精進1%&#xff0c;與百萬開發者共攀技術珠峰 更多內容持續更新中&#xff01;希望能給大家帶來…

Leetcode 206. 反轉鏈表 迭代/遞歸

原題鏈接&#xff1a;Leetcode 206. 反轉鏈表 解法一&#xff1a;迭代 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* …

C++11新特性 | 歡迎來到現代C++的世界!

左值與右值 左值與右值的概念 可以被取地址的值為左值&#xff08;left value&#xff0c;簡稱lvalue&#xff09;&#xff0c;否則為右值&#xff08;right value&#xff0c;簡稱rvalue&#xff09;。 常見的左值、右值例子&#xff1a; // >>>>>>> 左值…

因為對象裝箱拆箱導致的空指針異常

今天業務突然提了個事件單&#xff0c;客戶添加承租人一直報錯&#xff0c;但是很奇怪&#xff0c;報錯信息是空的二話不說&#xff0c;先跟API組要了接口和參數&#xff0c;然后看日志然鵝&#xff0c;這個接口并沒有打印日志&#xff0c;只有一個e.printStackTrace()然后靜下…

Rust 在 Windows 環境下交叉編譯其他操作系統可執行文件的詳細指南

前言&#xff1a;為什么需要交叉編譯&#xff1f; 想象一下這樣的場景&#xff1a;你在 Windows 電腦上開發了一個 Rust 程序&#xff0c;希望它能在 Linux 服務器上運行&#xff0c;或者在朋友的 macOS 電腦上測試 —— 總不能為了編譯不同系統的版本&#xff0c;專門買一臺 …

Ubuntu系統配置鏡像源

要修改的文件 /etc/apt/sources.list操作步驟 1. 備份原文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak2. 編輯文件 sudo nano /etc/apt/sources.list3. 清空文件內容&#xff0c;填入以下內容 先獲取Ubuntu版本代號&#xff1a; lsb_release -cs然后根據版本填…

【Spring Cloud Alibaba】Sentinel(一)

【Spring Cloud Alibaba】Sentinel&#xff08;一&#xff09;1. 簡介2. 服務雪崩1. 簡介 Sentinel 是阿里巴巴開源的分布式系統的流量防護組件&#xff0c;主要用來做流量控制、熔斷降級、系統保護。它的定位類似于 Hystrix&#xff0c;但更側重在 流量治理 上。目前在微服務…