Dockerfile與Dockerfile實戰

Dockerfile與Dockerfile實戰

前言

​ 先前我們在講述docker的鏡像構建時對Dockerfile做了初步介紹,本文將結合上次的內容做更加細緻的介紹,從回顧到實戰演練講述Dockerfile,本文先通過三個簡單的案例感受、理解Dockerfile,主要是寫httpd、sshd、以及systemctl的Dockerfile,之後會進行對其他服務如Nginx、Tomcat以及MySQL編寫並且測試Dockerfile。

回顧Dockerfile

​ 說到Dockerfile,就離不開Dockerfile的核心組件,尤其是鏡像。鏡像是運行容器的基礎環境,也就是說鏡像是docker容器創建的關鍵,而創建鏡像的三種方式之一的Dockerfile是最爲靈活的。

什麼是Dockerfile?

​ Dockerfile可以看做是被Docker程序所解釋翻譯的腳本,由一組命令集合而成,每一條命令都對應一條操作命令,有其翻譯爲Linux下的具體命令。用戶可以通過自定義內容來快速構建鏡像。

​ 其實說簡單點,你可以認爲Dockerfile是“專門用於構建鏡像的shell腳本”。

​ 還記得Dockerfile的嚴格格式嗎?我們先來看一下這個表格。

Dockerfile與Dockerfile實戰

​ Dockerfile是一種分層結構,其中的指令每一條都會構建一層鏡像及容器,只不過這是臨時的,除了基礎鏡像,其他中間產生的容器最後都會被清除。當然有時候會出現一些“無名氏”鏡像,標誌就是使用docker images命令時ID和tag都是none。

​ 出現none鏡像的原因有兩類:一則是好的none鏡像;二則是壞的none鏡像。好的none鏡像:代表的是中間鏡像,你可以認爲是父鏡像的子鏡像,可以使用docker images -a查看。這類鏡像不會佔用磁盤空間,但是佔用了屏幕顯示空間。壞的none鏡像:這類可能會導致磁盤空間問題。一般這種情況是舊鏡像更新產生。

​ 因此,一般情況我們都可以通過命令將none鏡像刪除(實戰中會給出)。

Dockerfile的作用是什麼?

​ Dockerfile的核心作用就是用戶可以靈活、快速、支持自定義構建所需鏡像。

簡述docker執行Dockerfile流程以及構建使用鏡像過程

docker執行Dockerfile流程

(1)docker從基礎鏡像運行一個容器;
(2)執行一條指令並對容器作出修改;
(3)執行類似docker commit的操作提交一個新的鏡像層;
(4)docker再基於剛提交的鏡像運行一個新容器;
(5)執行dockerfile中的下一條指令直到所有指令都執行完成。

構建使用鏡像過程

構建鏡像命令舉例:docker build -t image_name . (不要忽視這個點)

使用鏡像命令舉例:docker run -d -P image_name

最後使用docker ps -a 查看容器運行狀態,如果是up狀態就可以鏡像測試驗證了。

Dockerfile實戰

1、構建httpd服務鏡像

首先創建工作目錄

mkdir apache
cd apache

編寫Dockerfile

vim Dockerfile

#基於的基礎鏡像
FROM centos
#維護鏡像的用戶信息
MAINTAINER [email protected]
#鏡像操作指令安裝Apache軟件
RUN yum -y update
RUN yum -y install httpd
#開啓 80端口
EXPOSE 80
#複製網站首頁文件
ADD index.html /var/www/html/index.html
#將執行腳本複製到鏡像中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#啓動容器是執行腳本
CMD ["/run.sh"]

其中注意:run 命令可以有多條CMD只能有一條,若有多條則只會執行最後一條

編寫啓動httpd服務的shell腳本

vim run.sh

#!/bin/bash
rm -rf /run/httpd/*
exec /usr/sbin/apachectl -D FOREGROUND

編寫測試頁面

vim index.html

<h1>this is docker httpd web</h1>

使用tree命令查看目錄的文件結構

[root@localhost apache]# tree ./
./
├── Dockerfile
├── index.html
└── run.sh

0 directories, 3 files

構建和使用鏡像(創建運行容器)

[root@localhost apache]# docker build -t httpd:new .
#因爲我之前已經構建過,所以很快,此處案例顯示過程是爲了體現Dockerfile執行時的特徵:分層和中間容器及鏡像
Sending build context to Docker daemon  4.096kB
Step 1/9 : FROM centos:7
 ---> 5e35e350aded
Step 2/9 : MAINTAINER [email protected]
 ---> Using cache
 ---> 3a68b2812314
Step 3/9 : RUN yum -y update
 ---> Using cache
 ---> ecf1ecb0a774
Step 4/9 : RUN yum install -y httpd
 ---> Using cache
 ---> ae8c1ee32fbd
Step 5/9 : EXPOSE 80
 ---> Using cache
 ---> 29f12f1f7490
Step 6/9 : ADD index.html /var/www/html/index.html
 ---> Using cache
 ---> f56113e6b984
Step 7/9 : ADD run.sh /run.sh
 ---> Using cache
 ---> 886bf9e654ab
Step 8/9 : RUN chmod +x /run.sh
 ---> Using cache
 ---> bf53e19ad44f
Step 9/9 : CMD ["/run.sh"]
 ---> Using cache
 ---> 9500f0aefd1d
Successfully built 9500f0aefd1d
Successfully tagged httpd:new

[root@localhost apache]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
httpd                 new                 9500f0aefd1d        35 seconds ago      524MB
centos                7                   5e35e350aded        5 months ago        203MB
...//之後的案例將不再查看鏡像了哈!
#基於構建的鏡像創建並運行容器,給容器取名爲test
[root@localhost apache]# docker run --name test -d -P httpd:new  
b7ec122849c61e36adb4a8891a87126afb53b1d5edfa2fda2a1ea18afa1a3169
[root@localhost apache]# docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                      PORTS                   NAMES
b7ec122849c6        httpd:new             "/run.sh"                3 seconds ago       Up 3 seconds                0.0.0.0:32768->80/tcp   test

這樣我們進入容器中檢查一下這個頁面文件是否存在

[root@localhost apache]# docker exec -it test /bin/bash
[root@b7ec122849c6 /]# cat /var/www/html/index.html 
<h1>this is docker httpd web</h1>

那麼此時我們可以通過瀏覽器訪問宿主機ip地址結合端口號(32768)來訪問網站,結果如下:

Dockerfile與Dockerfile實戰

下面的案例構建就直接給出Dockerfile和構建測試命令了。主要介紹其中的關鍵點。

2、構建sshd鏡像

mkdir sshd 

cd sshd
#sshd服務的鏡像構建——基於Dockerfile
#首先先下載基礎鏡像centos,創建對應的工作目錄
#開始編寫nginx的Dockerfile
#第一步:基礎鏡像
FROM centos:7
#第二步:維護者信息
MAINTAINER [email protected]
#第三步:指令集
RUN yum -y update
RUN yum -y install openssh* net-tools lsof telnet passwd 
RUN echo '123123' | passwd --stdin root
#不以PAM認證登錄而是以密鑰對登錄(非對稱密鑰),即禁用ssh的PAM認證
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
#禁用ssh中PAM會話模塊
RUN sed -i '/^session\s\+required\s\+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd
#創建ssh工作目錄和權限設置
RUN mkdir -p /root/.ssh && chown root:root /root && chmod 700 /root/.ssh
#開放22端口
EXPOSE 22
#第四步:啓動容器時執行指令
CMD ["/usr/sbin/sshd","-D"]

構建鏡像和運行容器

[root@localhost sshd]# docker build -t sshd:new .
[root@localhost sshd]# docker run -d -P sshd:new 
c7991648efebd192eb29f1d4e3503e47e0581f55381ff7a23e545041ef5d3e67
[root@localhost sshd]# docker ps -a
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS                   NAMES
c7991648efeb        sshd:new            "/usr/sbin/sshd -D"   20 seconds ago      Up 20 seconds       0.0.0.0:32769->22/tcp   jolly_ishizaka
b7ec122849c6        httpd:new           "/run.sh"             20 minutes ago      Up 20 minutes       0.0.0.0:32768->80/tcp   test

測試

[root@localhost sshd]# ssh 20.0.0.149 -p 32769
The authenticity of host '[20.0.0.149]:32769 ([20.0.0.149]:32769)' can't be established.
RSA key fingerprint is SHA256:XLezVGFvOKIKW3fTBD0sIE9rsdz4021taphmcCo8IJM.
RSA key fingerprint is MD5:1e:86:94:2a:f5:a3:6c:e2:b4:b1:e4:50:9c:ad:8e:fb.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[20.0.0.149]:32769' (RSA) to the list of known hosts.
[email protected]'s password: 
[root@c7991648efeb ~]# exit
logout
Connection to 20.0.0.149 closed.

此時我們登錄該容器(ssh或者docker exec命令)查看sshd服務的狀態(但是systemctl無法使用)

[root@c7991648efeb ~]# systemctl status sshd
Failed to get D-Bus connection: Operation not permitted

一則我們可以使用下面的命令使用該命令,二則我們可以基於上面構建的鏡像作爲基礎鏡像構建systemctl的鏡像來測試驗證。

[root@localhost sshd]# docker run --privileged -itd -P sshd:new  /usr/sbin/init 
8dafa05dc12fc02f91dce93c6ab3085ab55eff1ee6b18c24731205e5c2ed37a9
[root@localhost sshd]# docker ps -a
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS                   NAMES
8dafa05dc12f        sshd:new            "/usr/sbin/init"      3 seconds ago       Up 3 seconds        0.0.0.0:32770->22/tcp   hardcore_mccarthy
c7991648efeb        sshd:new            "/usr/sbin/sshd -D"   20 minutes ago      Up 20 minutes       0.0.0.0:32769->22/tcp   jolly_ishizaka
b7ec122849c6        httpd:new           "/run.sh"             40 minutes ago      Up 40 minutes       0.0.0.0:32768->80/tcp   test
[root@localhost sshd]# ssh 20.0.0.149 -p 32770
The authenticity of host '[20.0.0.149]:32770 ([20.0.0.149]:32770)' can't be established.
ECDSA key fingerprint is SHA256:LU81jNjOCKaiWrCsxTLPmx+YsUMVOBa2rG/XLXQsv9E.
ECDSA key fingerprint is MD5:03:15:aa:8a:65:8a:cc:b4:fb:66:f8:f6:6c:89:84:7b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[20.0.0.149]:32770' (ECDSA) to the list of known hosts.
[email protected]'s password: 
[root@8dafa05dc12f ~]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-04-22 02:28:49 UTC; 33s ago
     Docs: man:sshd(8)
           man:sshd_config(5)

--privileged表示提權,使得容器真正具備root的權限

3、構建systemctl鏡像

mkdir systemctl
cd systemctl

創建Dockerfile

vim Dockerfile

FROM sshd:new
MAINTAINER [email protected]
ENV container docker
#下面的命令是放在一個鏡像層中執行的,可以減少鏡像層
#括號中的指令含義是遍歷進入的目錄文件,刪除除了systemd-tmpfiles-setup.service的所有文件,之後刪除一些其他文件
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*; \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*; \
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

構建運行及測試

[root@localhost systemctl]# docker build -t systemctl:new .
[root@localhost systemctl]# docker run --privileged -it -v /sys/fs/cgroup/:/sys/fs/cgroup:ro systemctl:new /usr/sbin/init
systemd 219 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
Detected virtualization docker.
Detected architecture x86-64.

Welcome to CentOS Linux 7 (Core)!

Set hostname to <e99fd581042a>.
[  OK  ] Reached target Paths.
[  OK  ] Reached target Local File Systems.
[  OK  ] Reached target Swap.
[  OK  ] Created slice Root Slice.
[  OK  ] Listening on Journal Socket.
[  OK  ] Created slice System Slice.
         Starting Create Volatile Files and Directories...
[  OK  ] Listening on Delayed Shutdown Socket.
[  OK  ] Reached target Slices.
         Starting Journal Service...
[  OK  ] Started Create Volatile Files and Directories.
[ INFO ] Update UTMP about System Boot/Shutdown is not active.
[DEPEND] Dependency failed for Update UTMP about System Runlevel Changes.
Job systemd-update-utmp-runlevel.service/start failed with result 'dependency'.
[  OK  ] Started Journal Service.
[  OK  ] Reached target System Initialization.
[  OK  ] Started Daily Cleanup of Temporary Directories.
[  OK  ] Reached target Timers.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
[  OK  ] Reached target Multi-User System.

重新開啓一個終端進行測試

[root@localhost systemctl]# docker ps -a
CONTAINER ID        IMAGE               COMMAND               CREATED              STATUS              PORTS                   NAMES
e99fd581042a        systemctl:new       "/usr/sbin/init"      About a minute ago   Up About a minute   22/tcp                  gifted_edison
8dafa05dc12f        sshd:new            "/usr/sbin/init"      6 minutes ago        Up 6 minutes        0.0.0.0:32770->22/tcp   hardcore_mccarthy
c7991648efeb        sshd:new            "/usr/sbin/sshd -D"   27 minutes ago       Up 27 minutes       0.0.0.0:32769->22/tcp   jolly_ishizaka
b7ec122849c6        httpd:new           "/run.sh"             46 minutes ago       Up 46 minutes       0.0.0.0:32768->80/tcp   test
[root@localhost systemctl]# docker exec -it gifted_edison /bin/bash
[root@e99fd581042a /]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:sshd(8)
           man:sshd_config(5)
[root@e99fd581042a /]# systemctl start sshd
[root@e99fd581042a /]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-04-22 02:36:18 UTC; 1s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 51 (sshd)
   CGroup: /docker/e99fd581042af009c4a15e9ab7bdd231c0052056051a1b18e9996f57eb7f2c6b/system.slice/sshd.service
           └─51 /usr/sbin/sshd -D

Apr 22 02:36:18 e99fd581042a systemd[1]: Starting OpenSSH server daemon...
Apr 22 02:36:18 e99fd581042a sshd[51]: WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several problems.
Apr 22 02:36:18 e99fd581042a sshd[51]: Server listening on 0.0.0.0 port 22.
Apr 22 02:36:18 e99fd581042a sshd[51]: Server listening on :: port 22.
Apr 22 02:36:18 e99fd581042a systemd[1]: Started OpenSSH server daemon.
#開啓sshd服務後進行訪問宿主機測試成功
[root@e99fd581042a /]# ssh 20.0.0.149 -p 22
The authenticity of host '20.0.0.149 (20.0.0.149)' can't be established.
ECDSA key fingerprint is SHA256:pT/8N0H/tNaMm4Zqh7u28Jm5EtmDkidSaih4lWzFIQY.
ECDSA key fingerprint is MD5:16:47:40:1f:40:1b:34:e9:ff:f9:15:7b:0b:f4:02:8b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '20.0.0.149' (ECDSA) to the list of known hosts.
[email protected]'s password: 
Last login: Wed Apr 22 10:35:20 2020 from 20.0.0.149
[root@localhost ~]# exit
登出
Connection to 20.0.0.149 closed.
[root@e99fd581042a /]# exit
exit

總結

​ 本文回顧了Dockerfile,結合三個案例(httpd服務、sshd服務、systemd服務)來深入理解Dockerfile構建鏡像的過程。其中我們需要理解的是

1、每個服務都需要有自己的目錄和文件

2、Dockerfile的分層和中間緩存鏡像和容器的創建和刪除特點

3、--privileged的作用

4、體會整個從構建鏡像、創建運行容器到測試驗證的過程

謝謝閱讀!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章