Docker的鏡像制作方法詳解
Docker的鏡像制作
1.1 鏡像的基本原理
Docker 的鏡像是創(chuàng)建容器的基礎,就是一個普通文件,是一個面向 Docker 容器的只讀模板。其實鏡像是一種輕量級、可執(zhí)行的獨立軟件包,用來打包軟件運行環(huán)境和基于運行環(huán)境開發(fā)的軟件,它包含運行某個軟件所需的所有內(nèi)容(包括代碼、運行時、庫、環(huán)境變量和配置文件),這個打包好的運行環(huán)境就是image鏡像文件。
例如:一個鏡像可以是一個完整的 CentOS 操作系統(tǒng)環(huán)境,稱為一個 CentOS 鏡像;也可以是一個安裝了 MySQL 的應用程序,稱之為一個 MySQL 鏡像等等。鏡像是一個靜態(tài)的概念,不包含任何動態(tài)數(shù)據(jù),其內(nèi)容在構建之后也不會被改變。
1、鏡像的底層加載原理
? Docker 的鏡像實際上由一層一層的文件系統(tǒng)組成,這種層級的文件系統(tǒng) UnionFS(聯(lián)合文件系統(tǒng))。
? UnionFS:是一種分層、輕量級并且高性能的文件系統(tǒng),它支持對文件系統(tǒng)的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統(tǒng)下(unite several directories into a single virtual filesystem)。Union 文件系統(tǒng)是 Docker 鏡像的基礎。鏡像可以通過分層來進行繼承,基于基礎鏡像(沒有父鏡像),可以制作各種具體的應用鏡像。
2、鏡像的結(jié)構
? 鏡像不是一個單一的文件,而是有多層構成??梢酝ㄟ^ docker history 鏡像 命令查看鏡像中各層內(nèi)容及大小,每層對應著 Dockerfile 中的一條指令。
Docker 鏡像默認存儲在 /var/lib/docker 目錄中 。容器其實是在鏡像的最上面加了一層讀寫層, 在運行容器里做的任何文件改動,都會寫到這個讀寫層。如果刪除了容器,也就刪除了其最上面的讀寫層,文件改動也就丟失了。Docker 使用存儲驅(qū)動管理鏡像每層內(nèi)容及可讀寫層的容器層。
1、分層結(jié)構的特點其實我們也會考慮 Docker 為什么會才用這種分層的結(jié)果,它有什么好處呢?最大的一個好處就是共享資源。
比如:有多個鏡像都從相同的 base 鏡像構建而來,那么宿主機只需在磁盤上保存一份 base 鏡像,同時內(nèi)存中也只需加載一份 base 鏡像,就可以為所有容器服務了。而且鏡像的每一層都可以被共享。
2、分層結(jié)構的特點Docker 鏡像都是只讀的,當容器啟動時,一個新的可寫層被加載到鏡像的頂部,這一層通常被稱為容器層,容器層之下的都叫鏡像層。

3、鏡像的制作方式
- 基于容器創(chuàng)建鏡像
基于現(xiàn)有容器創(chuàng)建主要使用 docker commit 命令,就是把一個容器里面運行的程序以及該程序的運行環(huán)境打包起來生成新的鏡像。
它的缺點是:在基礎鏡像之上做的操作不會記錄,別人不知道做了哪些操作,因此被稱為黑盒鏡像。
docker commit [選項] 容器ID/名稱 生成的鏡像:[標簽] -m:說明信息; -a:作者信息; -p:生成過程中停止容器的運行;
# 示例 [root@localhost ~]# docker run -d --name web1 nginx:latest //創(chuàng)建一個容器 [root@localhost ~]# docker ps -a //查看運行狀態(tài) [root@localhost ~]# docker commit web1 nginx:v1 //生成鏡像,生成之前先在容器里寫點東西 [root@localhost ~]# docker images //查看生成的鏡像 [root@localhost ~]# docker run -itd -p 80:80 --name web2 nginx:v1 //用生成的鏡像創(chuàng)建容器
- 基于Dockerfile創(chuàng)建常用基礎服務
除了手動生成 Docker 鏡像之外,可以使用 Dockerfile 自動生成鏡像。Dockerfile 是由一組指令組成的文件,其中每條指令對應 Linux 中的一條命令,Docker 程序?qū)⒆x取Dockerfile 中 的指令生成指定鏡像。
1.2 Dockerfile制作鏡像
鏡像的制作實際上就是定制每一層所添加的配置、文件等信息。但是命令畢竟只是命令,每次定制都得去重復執(zhí)行這個命令,而且還不夠直觀,如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定制鏡像。這個腳本就是我們說的 Dockerfile
Dockerfile 是一個文本文件,其內(nèi)包含了一條條的指令 (Instruction),每一條指令構建一層,因此每一條指令的內(nèi)容,就是描述該層應當如何構建。
1、Dockerfile常用指令
Dockerfile 結(jié)構大致分為四個部分:基礎鏡像信息、維護者信息、鏡像操作指令 和 容器啟動時執(zhí)行指令。Dockerfile 文件每行支持一條指令,每條指令可攜帶多個參數(shù),每運行一條指令,都會給基礎鏡像添加新的一層。

| 指令 | 解釋 |
|---|---|
| FROM 鏡像 | 指定基礎鏡像(新鏡像所基于的鏡像),第一條指令必須為 FROM 指令,每創(chuàng)建一個鏡像就需要一條 FROM 指令。 |
| MAINTAINER 名字 | 說明新鏡像的維護人信息(可以不寫) |
| RUN 命令 | 在所基于的鏡像上執(zhí)行命令,并提交到新的鏡像中 |
| CMD [“命令”,“參數(shù)”] | 指令啟動容器時默認要運行的命令或者腳本,如果指定多條則只能最后一條被執(zhí)行(如果在啟動容器時指定命令,則不起作用) |
| EXPOSE 端口號 | 指定新鏡像加載到 Docker 時要開啟的端口(只是定義,不更改) |
| ENV 環(huán)境變量 變量值 | 設置一個環(huán)境變量的值,會被后面的 RUN 使用 |
| ADD 源 目標 | 將宿主機文件拷貝到容器里面去,源文件要與 Dockerfile 文件在相同目錄中(源文件是壓縮包會自動解壓) |
| COPY 源 目標 | 將本地主機上的文件或目錄復制到容器里,源文件要與 Dockerfile 文件在相同的目錄中 |
| VOLUME [“目錄”] | 在容器中創(chuàng)建一個掛載點(自動創(chuàng)建匿名卷) |
| USER 用戶名/UID | 指定運行容器時的用戶 |
| WORKDIR 路徑 | 為后續(xù)的 RUN、CMD、ENTRYPOINT 指定工作目錄 |
| ONBUILD 命令 | 指定所生成的鏡像作為一個基礎鏡像時所要運行的命令 |
| HEALTHCHECK | 健康檢查,定義檢查指令 |
2、Dockerfile制作鏡像:案例
- 構建Nginx鏡像
[root@localhost ~]# docker tag hub.atomgit.com/amd64/centos:centos7 centos:7 //下載centos鏡像,并修改標簽
[root@localhost ~]# mkdir nginx;cd nginx
[root@localhost nginx]# vim Dockerfile
FROM centos:7
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/* && \
sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/* && \
sed -i 's/#baseurl=/baseurl=/g' /etc/yum.repos.d/* && \
yum -y install gcc make pcre-devel zlib-devel tar zlib
ADD nginx-1.12.0.tar.gz /usr/src/
RUN cd /usr/src/nginx-1.12.0 && \
mkdir -p /usr/local/nginx && \
./configure --prefix=/usr/local/nginx && \
make && make install && \
ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
RUN rm -rf /usr/src/nginx-1.12.0
EXPOSE 80
EXPOSE 443
CMD ["nginx","-g","daemon off;"]
[root@localhost nginx]# ls //將nginx源碼包拉上來
Dockerfile nginx-1.12.0.tar.gz
[root@localhost nginx]# docker build -t 鏡像:tag . //構建鏡像,要注意要在有Dockerfile文件的目錄執(zhí)行
- 構建LNMP鏡像
[root@localhost ~]# mkdir lnmp;cd lnmp
[root@localhost lnmp]# vim Dockerfile
FROM centos:7
# 安裝ngix
RUN rm -f /etc/yum.repos.d/* && \
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \
yum -y install epel-release && \
yum clean all && \
yum makecache && \
yum -y install nginx
RUN sed -i '/^user/s/nginx/nginx\ nginx/g' /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
# 安裝mariadb和php
RUN yum -y install mariadb-server mariadb-devel mariadb php-mysql php php-fpm
# 修改php-fpm配置文件
RUN sed -i '/^user/s/apache/nginx/g' /etc/php-fpm.d/www.conf && \
sed -i '/^group/s/apache/nginx/g' /etc/php-fpm.d/www.conf
# 聲明mariadb的用戶名和密碼
ENV MARIADB_USER=root
ENV MARIADB_PASS=123456
# 支持中文
ENV LC_ALL=en_US.UTF-8
# 添加并運行腳本
ADD db_init.sh /root/db_init.sh
RUN chmod 775 /root/db_init.sh
RUN /root/db_init.sh
ADD run.sh /root/run.sh
RUN chmod 775 /root/run.sh
ADD index.php /usr/share/nginx/html/index.php
# 開放的端口
EXPOSE 80
EXPOSE 3306
EXPOSE 443
EXPOSE 9000
# 每次創(chuàng)建容器運行此腳本
CMD ["/root/run.sh"]
[root@localhost lnmp]# vim default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
include fastcgi_params;
}
}
[root@localhost lnmp]# vim db_init.sh //數(shù)據(jù)庫初始化腳本
#!/bin/bash
#初始化數(shù)據(jù)庫命令
mysql_install_db --user=mysql
sleep 3
#啟動數(shù)據(jù)庫
mysqld_safe &
sleep 3
# 涉及到的變量在 Dockerfile 中都已經(jīng)聲明
mysqladmin -u "$MARIADB_USER" password "$MARIADB_PASS"
# 授權命令
mysql -u"$MARIADB_USER" -p"$MARIADB_PASS" -e "use mysql; grant all privileges on *.* to '$MARIADB_USER'@'%' identified by '$MARIADB_PASS' with grant option;"
mysql -u"$MARIADB_USER" -p"$MARIADB_PASS" -e "grant all privileges on *.* to '$MARIADB_USER'@'localhost' identified by '$MARIADB_PASS';"
h=$(hostname)
mysql -u"$MARIADB_USER" -p"$MARIADB_PASS" -e "use mysql; update user set password=password('$MARIADB_PASS') where user='$MARIADB_USER' and host='$h';"
[root@localhost lnmp]# vim run.sh //服務啟動腳本
#!/bin/bash
mysqld_safe &
/usr/sbin/nginx &
/usr/sbin/php-fpm
[root@localhost lnmp]# vim index.php
<?php
echo date("Y-m-d H:i:s")."<br />\n";
$link=mysql_connect("localhost","root","123456");
if(!$link) echo "FAILD!";
else echo "MySQL is OK!";
phpinfo();
?>
[root@localhost lnmp]# docker build -t centos:lnmp .
[root@localhost lnmp]# docker run -d --name lnmp -P centos:lnmp
1.3 多階段構建鏡像
在 Docker 17 版本后提供的,使用多階段構建可以在一個 Dockerfile 中使用多個 FROM 語句。每個FROM指令都可以使用不同的基礎鏡像,并表示開始一個新的構建階段。你可以很方便的將一個階段的文件復制到另一個階段,在最終的鏡像中留下你需要的內(nèi)容。
使用多階段構建的好處:
1.減小鏡像大小:每個構建階段只包含必要的依賴項和文件,從而減小了生成的鏡像大小。這可以減少鏡像的存儲空間和傳輸時間。
2.提高構建速度:每個構建階段可以一起執(zhí)行。而且,每個構建階段只構建所需的內(nèi)容,從而減少了構建時間。
3.簡化 Dockerfile:使用多個構建階段可以將 Dockerfile 分解為更小的部分,從而使Dockerfile 更加易于管理和維護。
4.提高安全性:使用多個構建階段可以限制敏感信息的泄露。例如,在第一個構建階段中,可以包含敏感信息,例如私有密鑰或密碼。而在第二個構建階段中,可以只包含必要的文件和依賴項
? 多階段構建案例(未使用多階段構建)
[root@localhost ~]# mkdir demo;cd demo
[root@localhost demo]# vim demo.c
# include<stdio.h>
int main()
{
printf("%s\n","This is a demo!");
return 0;
}
[root@localhost demo]# vim Dockerfile
FROM centos:7
ENV version=1.0
WORKDIR /demo
COPY demo.c .
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \
yum -y install gcc && \
gcc -v
RUN gcc demo.c -o demo && \
rm -rf demo.c && \
yum -y remove gcc && \
cp demo /usr/local/bin/
CMD ["demo"]
[root@localhost demo]# docker build -t demo:v1 .
[root@localhost demo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo v1 d05f8303b0bc 22 seconds ago 557MB
? 多階段構建案例(使用多階段構建)
[root@localhost demo]# vim Dockerfile //基于上面的未使用構建,添加這兩行
FROM centos:7
ENV version=1.0
WORKDIR /demo
COPY demo.c .
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \
yum -y install gcc && \
gcc -v
RUN gcc demo.c -o demo && \
rm -rf demo.c && \
yum -y remove gcc && \
cp demo /usr/local/bin/
FROM centos:7
# --from表示從其他階段拷貝內(nèi)容到本階段,0表示從第一個階段拷貝到本階段
COPY --from=0 /usr/local/bin/demo /usr/local/bin/demo
CMD ["demo"]
[root@localhost demo]# docker build -t demo:v1 .
[root@localhost demo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo v2 68bc7352dcfa 13 seconds ago 204MB //使用多階段構建
demo v1 d05f8303b0bc 9 minutes ago 557MB //未使用多階段構建總結(jié)
到此這篇關于Docker的鏡像制作方法的文章就介紹到這了,更多相關Docker鏡像制作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Docker配置MySql環(huán)境的實現(xiàn)步驟
通過使用Docker,開發(fā)人員可以更容易地構建、測試和交付應用程序,同時減少了環(huán)境配置和依賴項管理的復雜性,本文主要介紹了Docker配置MySql環(huán)境的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,感興趣的可以了解一下2024-02-02
docker(alpine+golang)?中?hosts?不生效問題解決方法
這篇文章主要介紹了docker(alpine+golang)?中?hosts?不生效問題解決大全,本文給大家分享了三種解決方法,每種方法給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07

