dockerfile
Dokcer鏡像的創建
創建鏡像有三種方法,分別為【基于已有鏡像創建】、【基于本地模板創建】以及【基于Dockerfile創建】。?
(1)首先啟動一個鏡像,在容器里做修改
docker run -itd --name web centos:7 /bin/bash ? ? #啟動容器
??
yum install -y epel-release ?#安裝epel源
yum install -y nginx ? ? ? ? #安裝nginx
yum install net-tools ? ? ? ?#安裝tools工具
nginx ? ? ? ? ? ? ? ? ? ? ? ?#啟動服務
netstat -natp |grep 80 ? ? ? #查看端口是否開啟
??
docker ps -a ? #查看容器ID
??
(2)然后將修改后的容器提交為新的鏡像,需要使用該容器的ID號創建新鏡像
docker commit -m "new nginx" -a "xxxx" 容器id nginx:centos7
?#常用選項:
?-m 指定說明信息;
?-a 指定作者信息;
?-p 生成過程中停止容器的運行。
?c7f4bc905c29 ?原容器ID。
?nginx:centos ?生成新的鏡像名稱。
??
docker images ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#查看生成的新鏡像
docker run -itd nginx:centos7 bash ? ? ? ? ? #使用新的鏡像創建容器
docker ps -a ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #查看容器狀態
docker exec -it 容器id bash ? ? ? ? ? ? ? ? ?#進入容器
nginx ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#啟動nginx服務
netstat -natp |grep 80 ? ? ? ? ? ? ? ? ? ? ? #查看80端口是否開啟
基于本地模板創建?
通過導入操作系統模板文件可以生成鏡像,模板可以從OPENVZ 開源項目下載,下載地址為:?
openvz.org/ Download/template/precreated
模板里面就是使用docker export 命令導出的容器文件
??
#下載模板
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
ebian 7.0已經是一個相對較舊的Linux發行版,其支持已經結束,
建議考慮使用更新版本的 Debian 或其他更現代的 Linux 發行版。
??
#導入為鏡像,兩種方法
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test ?#方法一
??
docker import debian-7.0-x86-minimal.tar.gz -- debian:test ?#方法二
??
#查看鏡像
docker images
??
#使用導入的鏡像創建容器
docker run -itd debian:test bash
docker ps -a
基于Dockerfile創建?
聯合文件系統(UnionFS )?
Union文件系統是Docker鏡像的基礎。鏡像可以通過分層來進行繼承,基于基礎鏡像(沒有父鏡像),
可以制作各種具體的應用鏡像。
特性: 一次同時加載多個文件系統,但從外面看起來,只能看到一一個文件系統,
聯合加載會把各層文件系統疊加起來,這樣最終的文件系統會包含所有底層的文件和目錄。
我們下載的時候看到的一層層的就是聯合文件系統。
鏡像加載原理?
Docker的鏡像實際上由一層一層的文件系統組成,這種層級的文件系統就是UnionFS。
rootfs:
rootfs 是指 Docker 鏡像中的根文件系統。它包含了一個完整的文件系統,包括所有的文件和目錄,
以及與之相關的權限、所有權等信息。在運行容器時,這個文件系統會被掛載到容器的根目錄。
Docker 鏡像是由一系列層(layers)組成的,每一層都包含文件系統的一部分。這些層在邏輯上疊加在一起,
形成最終的文件系統,而這個最終的文件系統就是 rootfs。
bootfs:
bootfs 是一個概念,通常用來描述 Docker 鏡像中用于引導的文件系統。
引導文件系統是用于啟動操作系統的文件系統,包含了啟動時所需的核心文件等。
在 Docker 中,bootfs 可以看作是鏡像中的一部分,它包含了啟動容器所需的最基本的文件。
bootfs主要包含bootloader和kernel,bootloader主要是引導加載kernel,Linux剛啟動時會加載bootfs文件系統。
在Docker鏡像的最底層是bootfs,這一層 與我們典型的Linux/Unix系統是一樣的, 包含boot加載器和內核。
當boot加載完成之 后整個內核就都在內存中了,此時內存的使用權已由bootfs轉交給內核,此時系統也會卸載bootfs。
rootfs,在bootfs之 上。包含的就是典型Linux系統中的/dev、/proc、/bin、/etc等標準目錄和文件。
rootfs就是各種不同的操作系統發行版,比如Ubuntu, Centos等。
bootfs就是內核引導器(引導加載內核)和內核。
rootfs是n多個基礎鏡像(提供基礎操作環境)和應用鏡像疊加在一起的只讀層。
運行的容器實例會在rootfs之上添加一個可讀可寫層。
容器中操作系統容量小的原因?
因為對于精簡的OS,rootfs可以很小, 只需要包含最基本的命令、工具和程序庫就可以了,
因為底層直接用宿主機的kernel,自己只需要提供rootfs就可以了。由此可見對于不同的linux發行版,
bootfs基本是一 致的, rootfs會 有差別,因此不同的發行版可以公用bootfs。
大部分鏡像是通用的,但如果專門基于某個版本創建的鏡像,在其他版本的操作系統中運行可能會有問題。
Docker鏡像結構的分層
鏡像不是一個單一的文件,而是有多層構成。容器其實是在鏡像的最上面加了一層讀寫層,
在運行容器里做的任何文件改動,都會寫到這個讀寫層。如果刪除了容器,也就刪除了其最上面的讀寫層,
文件改動也就丟失了。Docker使用存儲驅動管理鏡像每層內容及可讀寫層的容器層。
(1)Dockerfile中的每個指令都會創建一個新的鏡像層;
(2)鏡像層將被緩存和復用;
(3)當Dockerfile的指令修改了,復制的文件變化了,或者構建鏡像時指定的變量不同了,
對應的鏡像層緩存就會失效;
(4)某一層的鏡像緩存失效,它之后的鏡像層緩存都會失效;
(5)鏡像層是不可變的,如果在某一層中添加一個文件,然后在下一層中刪除它,
則鏡像中依然會包含該文件,只是這個文件在Docker 容器中不可見了。
Dockefile
Docker鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,
還包含了一些為運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。
鏡像不包含任何動態數據,其內容在構建之后也不會被改變。?
鏡像的定制實際上就是定制每一層所添加的配置、文件。
如果我們可以把每一層修改 安裝、構建、操作的命令都寫入一個腳本,
用這個腳本來構建、定制鏡像,那么鏡像構建透明性的問題、體積的問題就都會解決。
這個腳本就是Dockerfile。
我們需要定制首己額外的需求時,只需在Docketlle上添加或者修改指令,重新生成image 即可,
省去了敲命令的麻煩。就是描述該層應當如何構建。有了Dockerfile,當我們需要定制自己額外的需求時,
只需在Dockerfile上添加或者修改指令,重新生成image即可,省去了敲命令的麻煩。
除了手動生成Docker鏡像之外,可以使用bockerfile自動生成鏡像。
Dockerfile 是由多條的指令組成的文件,其中每條指令對應Linux中的一條命令,
Docker程序將讀取Dockerfile中的指令生成指定鏡像。
Dockerfile結構大致分為四個部分:基礎鏡像信息、維護者信息、鏡像操作指令和容器啟動時執行指令。
Dockerfile每行支持一條指令,每條指令可攜帶多個參數,支持使用以“#“號開頭的注釋。
Docker?le其實就是我們用來構建Docker鏡像的源碼,當然這不是所謂的編程源碼,而是一些命令的組合,
只要理解它的邏輯和語法格式,就可以編寫Docker?le了。
簡單點說,Docker?le的作用:它可以讓用戶個性化定制Docker鏡像。因為工作環境中的需求各式各樣,
網絡上的鏡像很難滿足實際的需求。
Docker?le常見命令:?
命令?? ? ? ? ? ? ? ? ? ? ? 作用
FROM ? ? ? ? ? ? ? ? ? image_name:tag?? ?聲明基礎鏡像
MAINTAINER ? ? ? ? ? ? user_name?? ? ? ?聲明鏡像的作者
ENV key value?? ? ? ? ? 設置環境變量 (可以寫多條)
RUN command?? ? ? ? ? ? ? 編譯鏡像時運行的腳本(可以寫多條)
CMD?? ? ? ? ? ? ? ? ? ? ? 設置容器的啟動命令
ENTRYPOINT?? ? ? ? ? ? ? 設置容器的入口程序
ADD source_dir/?le ? ? 將宿主機的文件復制到鏡像內,如果是一個壓縮文件,
dest_dir/?le ? ? ? ? ? 將會在復制后自動解壓。
? ? ? ? ? ? ? ? ? ? ? ?支持URL路徑下載源文件,
? ? ? ? ? ? ? ? ? ? ? ?但下載方式不能自動解壓。
COPY source_dir/?le ? ?和ADD相似,將宿主機的文件復制到鏡像內,
dest_dir/?le ? ? ? ? ? 但是如果有壓縮文件并不能解壓。不支持URL路徑下載。
? ? ? ? ? ?
WORKDIR path_dir?? ? ? 設置工作目錄
ARG?? ? ? ? ? ? ? ? ? ? ? 設置工作目錄
VOLUMN?? ? ? ? ? ? ? ? ? 設置容器的掛載卷
FROM: 指定新鏡像的基礎鏡像。
MAINTAINER: 提供有關鏡像維護人的信息(已棄用,由LABEL替代)。
RUN: 在基礎鏡像上執行命令,并提交結果到新鏡像。每一個RUN都是鏡像的一層,分層越多,鏡像越大
ENTRYPOINT: 設置容器運行時的默認命令及參數。
CMD: 指定容器運行時的默認命令(可以在運行時被覆蓋)。
EXPOSE: 告訴Docker容器在運行時監聽指定的網絡端口(容器端口)。
ENV: 為后續指令設置環境變量,會被后面的RUN使用
ADD: 將文件從源路徑復制到鏡像的目標路徑,支持URL和自動解壓。
COPY: 將文件從源路徑復制到鏡像的目標路徑(僅限本地文件)。
VOLUME: 創建一個掛載點并指定為可在外部掛載的點。
USER: 設置運行鏡像時使用的用戶或UID。
WORKDIR: 為后續指令設置工作目錄。
ONBUILD: 指定當該鏡像作為另一個構建的基礎時要運行的命令。
ARG: 定義在Dockerfile中用于構建時由用戶傳遞的變量。ARG 用于構建時的參數傳遞,
而 ENV 用于在容器運行時設置環境變量。
-------------------------------------CMD和ENTRYPOINT的區別---------------------------------------------------------
[root@docker1 cmd]# cat dockerfile?
# Dockerfile
# 使用基礎鏡像
FROM centos:7
# 設置作者信息
MAINTAINER "Your Name <your.email@example.com>"
# 使用 ENTRYPOINT 指令設置容器啟動時執行的默認命令
ENTRYPOINT ["echo","hello"]
# 使用 CMD 指令設置默認參數,這些參數會傳遞給 ENTRYPOINT 指令中的命令
CMD ["WORLD"]
docker build -t centos5:test .
docker run -it --name test centos:test ls /etc ?#不要加d,否則會后臺運行。
一個dockerfile中一般只有有一個ENTRYPOINT和CMD,多個ENTRYPOINT和CMD只會執行最后一個。
ENTRYPOINT 指定的命令會在容器啟動時執行,并且這個命令會成為容器的主進程。
主進程負責接收信號,處理容器的生命周期,并且在主進程退出時容器也會終止。
ENTRYPOINT的指令不會被覆蓋,而CMD的命令在構建鏡像時,使用docker run 加上參數會覆蓋CMD的指令。
ENTRYPOINT設定容器啟動時第一個運行的命令;
CMD是啟動容器時默認執行的命令,如果指定多條CMD命令,只執行最后一條命令。
如果在docker run時指定了命令或者鏡像中有ENTRYPOINT,那么CMD就會被覆蓋,
并且會將CMD中的命令作為參數傳給ENTRYPOINT。
CMD可以為ENTRYPOINT進行傳參。
----------------------------RUN命令的優化------------------------------------------------------------
&& 符號:
RUN ls /opt && yum -y insatll nginx
#&& 連接多個命令,確保前一個命令成功后才執行下一個命令
分號 ;:
使用分號可以在一行中連接多個命令,不管前一個命令是否成功,后面的命令都會被執行。
dockerfile
Copy code
RUN command1 ; command2 ; command3
雙豎線 ||:
雙豎線表示“或者”,如果前一個命令失敗,才會執行后面的命令。
dockerfile
Copy code
RUN command1 || command2
反斜杠 \:
反斜杠可以用來將一行命令拆分成多行,提高可讀性。相當于換行
dockerfile
Copy code
RUN command1 \
? ? && command2 \
? ? && command3
-------------------------------------copy和add的區別-------------------------------------------------
ADD和COPY比較:(同樣需求下,官方推薦使用 COPY)
1、共同點:
ADD和COPY都可以復制本地文件到鏡像中。
2、區別:
ADD:如果是一個壓縮文件,ADD會在復制后自動解壓。且支持URL路徑下載源文件,但URL下載和解壓特性不能一起使用,
任何壓縮文件通過URL拷貝,都不會自動解壓。
COPY:如果是壓縮文件,COPY并不能解壓。且COPY只能復制本地文件,不支持URL路徑拷貝。
ADD 的優點: 在執行 <源文件> 為 tar 壓縮文件的話,壓縮格式為 gzip、bzip2 以及 xz 的情況下,
會自動復制并解壓到 <目標路徑>。
ADD 的缺點: 在不解壓的前提下,無法復制 tar 壓縮文件。會令鏡像構建緩存失效,
從而可能會令鏡像構建變得比較緩慢。具體是否使用,可以根據是否需要自動解壓來決定。
構建一個httpd的dockerfile:
FROM centos:7
MAINTAINER this is my ?diy apache <dn>
RUN yum install -y gcc gcc-c++ make pcre pcre-devel expat-devel perl
ADD apr-1.6.2.tar.gz /opt/
ADD apr-util-1.6.0.tar.gz /opt/
ADD httpd-2.4.29.tar.bz2 /opt/
RUN mv /opt/apr-1.6.2 /opt/httpd-2.4.29/srclib/apr && mv /opt/apr-util-1.6.0 /opt/httpd-2.4.29/srclib/apr-util &&\
cd /opt/httpd-2.4.29/ &&\
./configure --prefix=/usr/local/httpd --enable-so --enable-rewrite --enable-charset-lite --enable-cgi &&\
make -j 4 && make install
EXPOSE 80
CMD ["/usr/local/httpd/bin/apachectl","-D","FOREGROUND"]
docker build -t apache:centos .
鏡像容量過大的解決方案?
基礎鏡像盡量使用輕量級最小化的鏡像。
Dockerfile中盡量把RUN指令合并在一起,減少鏡像的層數(因為每一個RUN指令就是一個鏡像層)。
多級構建(拿Dockerfile構建好的鏡像再構建一次)。
#基層鏡像
FROM centos:7 AS first
#鏡像作者信息描述
MAINTAINER this is apache image <yh 2022-11-23 >
#指定的Linu執行腳本
RUN yum -y install gcc gcc-c++ make pcre pcre-devel expat-devel perl
#將源碼編譯的安裝包安放到容器中并進行解壓
ADD apr-1.6.2.tar.gz /opt/
ADD apr-util-1.6.0.tar.gz /opt/
ADD httpd-2.4.29.tar.bz2 /opt/
#進行源碼編譯安裝
RUN mv /opt/apr-1.6.2 /opt/httpd-2.4.29/srclib/apr && mv /opt/apr-util-1.6.0 /opt/httpd-2.4.29/srclib/apr-util && cd /opt/httpd-2.4.29 && ./configure --prefix=/usr/local/httpd --enable-so --enable-rewrite --enable-charset-lite --enable-cgi && make -j 4 && make install
#二階段構建
FROM centos:7
#將一階段的已安裝好的包安防到二階端中,并舍棄一階段的其他無用資源
COPY --from=first ?/usr/local/httpd ?/usr/local/httpd
#安裝apache運行所需的環境依賴包,不再安裝源碼編譯所需的依賴包
RUN yum install -y pcre pcre-devel expat-devel perl
EXPOSE 80
ENTRYPOINT ["/usr/local/httpd/bin/apachectl","-D","FOREGROUND"]
docker build -t apache1:centos .
基于centos 構建一個 nginx的dockefile
#創建目錄存放相關文件
mkdir nginxdockerfile
cd nginxdockerfile
echo "docker nginx build successful" > index.html
vi Dockerfile
FROM centos:7
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /usr/local/src
ENV NG_VERSION=nginx-1.25.1
RUN yum -y install epel-release
RUN yum -y install wget
RUN wget http://nginx.org/download/$NG_VERSION.tar.gz && tar xzvf $NG_VERSION.tar.gz?
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel && yum install -y pcre-devel libxslt-devel gd-devel GeoIP GeoIP-devel GeoIP-data
RUN yum clean all?
RUN useradd -M -s /sbin/nologin nginx?
WORKDIR /usr/local/src/$NG_VERSION?
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make && make install
ADD index.html /usr/local/nginx/html?
VOLUME /usr/local/nginx/html?
ENV PATH /usr/local/nginx/sbin:$PATH?
EXPOSE 80/tcp?
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
##構建鏡像
docker build -t centos7:nginx .
#創建容器
docker run -d --name nginx -p 8080:80 centos7:nginx
訪問
Htpp:網址:8080
z注釋:
#基準鏡像
FROM centos:7
#作者信息
LABEL version="nginx v1"
LABEL "emill"="2@qq.com"
#調整系統時間差
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#工作目錄
WORKDIR /usr/local/src/?
#定義環境變量
ENV NG_VERSION nginx-1.21.0?
#安裝epel倉庫
RUN yum -y install epel-release?
#安裝wget
RUN yum -y install wget?
#下載nginx文件并解壓
RUN wget http://nginx.org/download/$NG_VERSION.tar.gz && tar xzvf $NG_VERSION.tar.gz?
#安裝編譯依賴包
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel && yum install -y pcre-devel libxslt-devel gd-devel GeoIP GeoIP-devel GeoIP-data
#清理倉庫
RUN yum clean all?
#創建nginx用戶
RUN useradd -M -s /sbin/nologin nginx?
#切換工作目錄
WORKDIR /usr/local/src/$NG_VERSION?
#編譯安裝nginx
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make && make install
#復制測試頁面到容器中
ADD index.html /usr/local/nginx/html?
#設置容器中要掛在到宿主機的目錄
VOLUME /usr/local/nginx/html?
#設置sbin環境變量
ENV PATH /usr/local/nginx/sbin:$PATH?
#暴露80端口
EXPOSE 80/tcp?
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
#當ENTRYPOINT和CMD連用時,CMD的命令是ENTRYPOINT命令的參數,兩者連用相當于nginx -g "daemon off;"而當一起連用的時候命令格式最好一致(這里選擇的都是json格式的是成功的,如果都是sh模式可以試一下)
1.FROM
功能為指定基礎鏡像,并且必須是第一條指令。 如果不以任何鏡像為基礎,那么寫法為:FROM scratch。 同 時意味著接下來所寫的指令將作為鏡像的第一層開始
2.RUN
功能為運行指定的命令
注意:多行命令不要寫多個RUN,原因是Dockerfile中每一個指令都會建立一層. 多少個RUN就構建了多 少層鏡像,會造成鏡像的臃腫、多層,不僅僅增加了構件部署的時間,還容易出錯。 RUN書寫時的換行 符是\
3.CMD
功能為容器啟動時要運行的命令
注意:補充細節:這里邊包括參數的一定要用雙引號,就是",不能是單引號。千萬不能寫成單引號。 原因是參數傳遞后,docker解析的是一個JSON array
4.RUN和CMD的區別
不要把RUN和CMD搞混了。 RUN是構件容器時就運行的命令以及提交運行結果 CMD是容器啟動時執行的命 令,在構件時并不運行,構件時緊緊指定了這個命令到底是個什么樣子
5.LABEL
功能是為鏡像指定標簽,為鏡像寫一些注釋信息
但是并不建議這樣寫,最好就寫成一行,如太長需要換行的話則使用\符號 如下:
注意:LABEL會繼承基礎鏡像種的LABEL,如遇到key相同,則值覆蓋
6.EXPOSE
功能為暴漏容器運行時的監聽端口給外部 但是EXPOSE并不會vim 使容器訪問主機的端口 如果想使得容器與主 機的端口有映射關系,必須在容器啟動的時候加上 -P參數
注意:如果在端口號后面加/tcp,默認為tcp協議,如果需要UDP端口需要添加/udp
7.ENV
功能為設置環境變量
8.ADD
一個復制命令,把文件復制到鏡象中。 如果把虛擬機與容器想象成兩臺linux服務器的話,那么這個命令就類似 于scp,只是scp需要加用戶名和密碼的權限驗證,而ADD不用。
注意:盡量不要把寫成一個文件夾,如果是一個文件夾了,復制整個目錄的內容,包括文件系統元數據
9.WORKDIR
設置工作目錄,對RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在則會創建,也可以設置多次
10.VOLUME
可實現掛載功能,可以將內部文件夾掛載到外部
11.ENTRYPOINT
該命令與CMD類似,用于執行命令使用,還可以與CMD命令一起拼合使用
它與CMD的區別: ? 相同點:只能寫一條,如果寫多條,那么只有最后一條生效
不同點:CMD在創建容器時,在后面添加其他的CMD指令,CMD會被覆蓋,但是ENTRYPOINT不會被覆蓋,如果兩個同時使用,CMD會變成ENTRYPOINT的參數