一、什么是 Dockerfile?
????????dockerfile 是用來構(gòu)建 docker 鏡像的命令參數(shù)腳本文件。
????????鏡像的定制實際上就是定制每一層所添加的配置、文件。如果我們可以把每一層修改、安裝、構(gòu)建、操作的命令都寫入一個腳本,用這個腳本來構(gòu)建、定制鏡像,那么之前提及的無法重復(fù)的問題、鏡像構(gòu)建透明性的問題、體積的問題就都會解決。這個腳本就是 Dockerfile。
????????Dockerfile 是一個文本文件,其內(nèi)包含了一條條的指令 (Instruction),每一條指令構(gòu)建一層,因此每一條指令的內(nèi)容, 就是描述該層應(yīng)當(dāng)如何構(gòu)建。
二、Dockerfile 規(guī)則:
1、格式
????????# 是注釋,指令建議要大寫,內(nèi)容小寫。這樣更能區(qū)分。比如:FROM centos
2、執(zhí)行順序
????????docker 是按照 Dockerfile 指令順序依次執(zhí)行的,也就是說從上到下。
3、其他
????????每一個 Dockerfile 的第一行都是非注釋性的,也就是說第一行不能是注釋,必須是 FROM 指令,來指定基礎(chǔ)鏡像,后面的指令都以基礎(chǔ)鏡像為運行環(huán)境。如果構(gòu)建過程中本地沒有指定鏡像文件,就會去遠端倉庫拉。
三、Dockerfile 指令:
前提:
????????首先根據(jù)自己的需要在指定目錄下先創(chuàng)建一個 dockerfile 文件,我是在 /usr/local/dockerfile 目錄下創(chuàng)建的自己的?xhf_dockerfile?文件。如下圖所示。
????????接下來我們要說的這些標(biāo)簽,都是這個 xhf_dockerfile?文件里面的內(nèi)容。
FROM 標(biāo)簽
????????這個 FROM 指令是 dockerfile 的第一個指令,然后指定了基礎(chǔ)鏡像,后面的所有指令都是運行在該基礎(chǔ)鏡像環(huán)境上的。
# tag 是可選的,如果不使用這兩個值時,會使用 latest 版本的基礎(chǔ)鏡像
FROM <image>
FROM <image>:<tag>
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
MAINTAINER?標(biāo)簽
????????該指令是描述的維護者信息。
MAINTAINER <name>
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
ENV?標(biāo)簽
????????該指令是用于定義環(huán)境變量的
# 兩種寫法都可以滿足
ENV <key>=<value>
ENV <key> <value>
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
# 定義一個變量 MYPATH,路徑為 /usr/local
ENV MYPATH /usr/local
WORKDIR?標(biāo)簽
????????該指令是切換到?WORKDIR 目錄下工作,這個與 linux 里面的 cd 差不多。如果 WORKDIR 不存在,它將被創(chuàng)建。
????????需要注意的是通過 WORKDIR 設(shè)置工作目錄后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、 COPY 等命令都會在該目錄下執(zhí)行。在使用 docker run 運行容器時,可以通過 -w 參數(shù)覆蓋構(gòu)建時所設(shè)置的工作目錄。
WORKDIR /usr/workdir
# 這時工作目錄為/a
WORKDIR /a
# 這時工作目錄為/a/b
WORKDIR b
# 這時工作目錄為/a/b/c
WORKDIR c
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
# 定義一個變量 MYPATH,路徑為 /usr/local
ENV MYPATH /usr/local
# 切換到 MYPATH 的路徑下
WORKDIR $MYPATH
????????這個命令啥時候會生效呢?會等我們進入容器的時候生效,下面這個截圖是如果我們不加這行命令創(chuàng)建的容器,默認(rèn)進入時候的路徑。?
????????下面這個截圖是加了這行命令后,進入容器默認(rèn)的當(dāng)前路徑。
RUN?標(biāo)簽
????????該指令用于在容器中執(zhí)行命令。我們常用來安裝基礎(chǔ)軟件,或者執(zhí)行一些命令。
? ? ? ? 需要注意的是 RUN 指令創(chuàng)建的中間鏡像會被緩存,并會在下次構(gòu)建中使用。如果不想使用這些緩存鏡像,可以在構(gòu)建時指定 --no-cache 參數(shù),如:docker build --no-cache
# 第一種 shell 執(zhí)行,eg: RUN mkdir /usr/local/tomcat/webapps/ROOT
RUN <command>
# 第二種 exec 執(zhí)行,eg:echo 'Hello xhf Docker'>/usr/local/tomcat/webapps/ROOT/index.html
RUN ["executable", "param1", "param2"]
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
# 定義一個變量 MYPATH,路徑為 /usr/local
ENV MYPATH /usr/local
# 切換到 MYPATH 的路徑下
WORKDIR $MYPATH
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
????????也可以這么用
# 安裝 yum 工具
RUN yum -y install vim
# 安裝網(wǎng)絡(luò)監(jiān)測工具
RUN yum -y install net-tools
ADD?標(biāo)簽
????????該指令是用來將宿主機某個文件或目錄放到(復(fù)制)容器某個目錄下面。
????????如果復(fù)制的文件是 tar?類型的,那么該文件會自動解壓?(?網(wǎng)絡(luò)壓縮資源不會被解壓?)?,可以訪問網(wǎng)絡(luò)資源,類似 wget。
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
? ? ? ? ?我們自己創(chuàng)建一個?index.html 文件用于測試,內(nèi)容很簡單。
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
# 定義一個變量 MYPATH,路徑為 /usr/local
ENV MYPATH /usr/local
# 切換到 MYPATH 的路徑下
WORKDIR $MYPATH
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
# 將 index.html 放到指定的目錄下
ADD index.html /usr/local/tomcat/webapps/ROOT/index.html
EXPOSE?標(biāo)簽
????????該指令用于暴露容器里的端口,沒有什么用,加了和不加沒有什么區(qū)別,僅僅是為了告訴使用這個鏡像的人,我的這個容器用到了 xxxx 端口號。
EXPOSE 端口
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 作者的名字為 xhf ,郵箱是1982392926@qq.com
MAINTAINER xhf<1982392926@qq.com>
# 定義一個變量 MYPATH,路徑為 /usr/local
ENV MYPATH /usr/local
# 切換到 MYPATH 的路徑下
WORKDIR $MYPATH
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
# 將 index.html 放到指定的目錄下
ADD index.html /usr/local/tomcat/webapps/ROOT/index.html
# 對外暴露 8080 端口
EXPOSE 8080
build 標(biāo)簽
? ? ? ? 該標(biāo)簽用于構(gòu)建鏡像,我們先執(zhí)行一下我上面的這些命令,驗證一下,將目錄切換到?/usr/local/dockerfile 下,因為我的?xhf_dockerfile 文件在這個目錄下面,執(zhí)行以下的命令:
docker build -f xhf_dockerfile -t mytomcat:0.1 .
# -f xhf_dockerfile 表示構(gòu)建的文件路徑
# -t 鏡像名稱:版本號
# . 表示當(dāng)前路徑
# 如果你當(dāng)前的目錄下只有一個 dockerfile 文件,那么可以省略 -f 參數(shù),如下所示:
docker build -t mytomcat:0.1 .
? ? ? ? 執(zhí)行完命令之后,我們可以看下鏡像是否成功創(chuàng)建了?
????????然后用我們自己的鏡像創(chuàng)建容器,輸入命令如下所示:
docker run --rm -d --name tomcat-8082 -p 8082:8080 mytomcat:0.1
????????接下來我們需要驗證兩個東西,第一個東西是當(dāng)我們進入到容器里面,默認(rèn)的目錄是不是 /usr/local ,第二個需要驗證的是訪問 tomcat 看是否可以出現(xiàn)登錄頁,因為登錄頁是我們自己復(fù)制過去的,如下所示,這兩個需要驗證的東西都沒有問題。
COPY?標(biāo)簽
????????該標(biāo)簽功能類似于 ADD 標(biāo)簽,但是是不會自動解壓文件,也不能訪問網(wǎng)絡(luò)資源。
COPY <源路徑> <目標(biāo)路徑>
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
# 將 index.html 復(fù)制到指定的目錄下
COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
VOLUME?標(biāo)簽
????????該標(biāo)簽用于在 image 中創(chuàng)建一個掛載目錄,以掛載宿主機上的目錄。
# path 代表容器中的目錄,與 docker run 不同,Dockerfile 中不能指定宿主機目錄,默認(rèn)使用 docker 管理的掛載點
VOLUME <path>
VOLUME ["path"]
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
# 將 index.html 復(fù)制到指定的目錄下
COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
# 創(chuàng)建兩個掛載點
VOLUME ["/data1","/data2"]
????????1、我們先使用?run -v 指定容器和宿主機的目錄進行掛載,執(zhí)行命令
docker run --rm -d --name tomcat-8081 -p 8081:8080 -v /usr/local/docker/ROOT:/usr/local/tomcat/webapps/ROOT tomcat:8
????????查看當(dāng)前容器的掛載信息,如下所示,掛載的路徑是我們上面指定的宿主和容器的路徑,沒有問題。
????????2、再次使用 docker run -v 參數(shù),但不指定宿主機的目錄,執(zhí)行命令
docker run --rm -d --name tomcat-8082 -p 8082:8080 -v /usr/local/tomcat/webapps/ROOT tomcat:8
????????從下面可以看到,Source 的路徑是自動分配的一個目錄
????????3、使用 dockerfile 中掛載點進行測試。通過 docker run 命令的 -v 標(biāo)識創(chuàng)建的掛載點只能對創(chuàng)建的容器有效。而通過 dockerfile 的 VOLUME 指令可以在鏡像中創(chuàng)建掛載點,這樣只要通過該鏡像創(chuàng)建的容器都有了掛載點。但在 dockerfile 中無法指定主機上對應(yīng)的目錄,是自動生成的。相當(dāng)于不指定宿主機的目錄創(chuàng)建掛載點。執(zhí)行下面的語句進行測試查看。
# 指定基礎(chǔ)鏡像為 tomcat:8
FROM tomcat:8
# 在容器的指定目錄下創(chuàng)建一個 ROOT 文件夾
RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
# 將 index.html 復(fù)制到指定的目錄下
COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
# 創(chuàng)建兩個掛載點
VOLUME ["/data1","/data2"]
# 構(gòu)建鏡像
docker build -f xhf_dockerfile -t mytomcat:0.3 .
# 構(gòu)建容器
docker run --rm -d --name tomcat-8083 -p 8083:8080 mytomcat:0.3
????????查看掛載點,會發(fā)現(xiàn)一共有兩個自動掛載的目錄,如下圖所示:
CMD 標(biāo)簽
????????該標(biāo)簽是構(gòu)建容器后調(diào)用的,也就是在容器啟動時才進行調(diào)用。
????????一個 Dockerfile 只有一個 CMD 指令,若有多個,只有最后一個 CMD 指令生效。
????????CMD 主要目的:為容器提供默認(rèn)執(zhí)行的命令,這個默認(rèn)值可以包含可執(zhí)行文件,也可以不包含可執(zhí)行文件,意味著必須指定 ENTRYPOINT 指令(第二種寫法)。
????????注意和 RUN 指令的區(qū)別,RUN 是構(gòu)建鏡像時執(zhí)行的命令,執(zhí)行的時期不同。
# shell格式
CMD <命令>
# exec格式
CMD ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2", …]
????????修改我們的?xhf_dockerfile 文件,改寫成下面的內(nèi)容:
# 指定基礎(chǔ)鏡像為 centos:7
FROM centos:7
CMD echo "This is a test."
????????執(zhí)行下面的命令,并且啟動容器,如下所示,我們可以看到可以正常執(zhí)行 CMD 標(biāo)簽的內(nèi)容。
# 構(gòu)建鏡像
docker build -f xhf_dockerfile -t mycentos:0.1 .
# 啟動容器
docker run mycentos:0.1
ENTRYPOINT?標(biāo)簽
????????該標(biāo)簽是指定容器啟動的要運行的命令,可以追加命令。
????????ENTRYPOINT 與 CMD 非常類似,不同的是通過 docker run 執(zhí)行的命令不會覆蓋ENTRYPOINT,而 docker run 命令中指定的任何參數(shù),都會被當(dāng)做參數(shù)再次傳遞給?ENTRYPOINT。
????????Dockerfile 中只允許有一個 ENTRYPOINT 命令,多指定時會覆蓋前面的設(shè)置,而只執(zhí)行最后的 ENTRYPOINT 指令。
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2 (shell內(nèi)部命令)
????????修改我們的?xhf_dockerfile 文件,改寫成下面的內(nèi)容:
# 指定基礎(chǔ)鏡像為 centos:7
FROM centos:7
ENTRYPOINT ["echo", "dockerfile-entrypoint test"]
ENTRYPOINT ["ls", "-a"]
????????執(zhí)行下面的命令,并且啟動容器,如下所示,我們可以看到可以?ENTRYPOINT?標(biāo)簽的只執(zhí)行了最后一行。
# 構(gòu)建鏡像
docker build -f xhf_dockerfile -t mycentos:0.2 .
# 啟動容器
docker run mycentos:0.2
????????接下來我們在 docker run 命令行種追加命令參數(shù),新添加的參數(shù)會追加到原 dockerfile 的?ENTRYPOINT 命令里。
????????相當(dāng)于在 Dockerfile 的 ENTRYPOINT 里追加了 -l 的參數(shù),即【ls -a -l】。啟動容器,如下所示,我們發(fā)現(xiàn)是可以正常執(zhí)行的。
? ? ? ? ?我們再追加一些錯誤的參數(shù),看看容器啟動的時候會不會報錯,如下所示,是會報錯的。
CMD 和?ENTRYPOINT 配合使用
????????一般情況下,ENTRYPOINT 和 CMD 標(biāo)簽都是互相配合使用的,即:ENTRYPOINT 填寫固定的命令,CMD 填寫該固定命令對應(yīng)的參數(shù),CMD 將這個參數(shù)傳遞給 ENTRYPOINT命令??梢岳斫鉃?CMD 參數(shù)為 ENTRYPOINT 的默認(rèn)值,如果項目中使用的不是 CMD 的默認(rèn)值,就可以在啟動 docker 容器時添加上真實的參數(shù)值,用來覆蓋 CMD 的默認(rèn)值。
? ? ? ? 舉個例子,比如要在鏡像中通過 java -jar 的方式啟動一個 java 工程,就可以采用下面的方式,默認(rèn)啟動的時候 commcon.jar 這個工程。
ENTRYPOINT ["java", "-jar"]
CMD ["common.jar"]
? ? ? ? 如果我們不想啟動這個 common.jar 的工程了,我們在啟動容器的時候更換下命令就可以了,如下所示:
docker run 容器名稱 xxxx.jar
實戰(zhàn)生成 jdk 鏡像:
? ? ? ? 接下來我們測試下 CMD 和?ENTRYPOINT 標(biāo)簽,在實際應(yīng)用中到底是不是按照我們想象的這種方式執(zhí)行。
????????第一步、新建兩個 springboot?工程,很簡單的就可以,命名為?DockerTestOne? 和?DockerTestTwo,主要的內(nèi)容我簡單的貼下,如下所示,這兩個工程唯一的區(qū)別就是名字和輸出不一樣,其他的都一樣。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
//將springboot應(yīng)用驅(qū)動起來
SpringApplication.run(App.class, args);
}
}
@RestController
public class HelloWorld {
@RequestMapping("/hello")
public String Hello(String name) {
return "Hello"+name+" from DockerTestOne";
}
}
@RestController
public class HelloWorld {
@RequestMapping("/hello")
public String Hello(String name) {
return "Hello"+name+" from DockerTestOne";
}
}
????????構(gòu)建出兩個可執(zhí)行的 jar 包,分別重命名為?docker_testone.jar 和?docker_testtwo.jar 。然后將這兩個 jar 包復(fù)制到 xhf_dockerfile 同等級的目錄下備用。
????????第二步、下載一個 linux 環(huán)境的 jdk,下載地址是這個,然后也把這個 jdk 復(fù)制到上面說的目錄下,如圖所示:
????????第三步、修改 xhf_dockerfile 文件,內(nèi)容如下所示:
FROM centos:7
MAINTAINER xhf<1982392926@qq.com>
ADD jdk-8u371-linux-x64.tar.gz /usr/local/
ADD docker_testone.jar /usr/local/
ADD docker_testtwo.jar /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_371
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV PATH $JAVA_HOME/bin
ENTRYPOINT ["java", "-jar"]
CMD ["docker_testone.jar"]
????????第四步、創(chuàng)建鏡像并啟動容器,如下所示:
docker build -f xhf_dockerfile -t mycentos:0.4 .
docker run -d -p 8080:8080 --name mycentos mycentos:0.4
????????第五步、在瀏覽器輸入?http://localhost:8080/hello?name=World,結(jié)果如下所示,我們發(fā)現(xiàn)我們的服務(wù)可以正常啟動和訪問。
????????第六步、關(guān)掉服務(wù),刪除容器,重新啟動容器,命令如下,我們發(fā)現(xiàn)我們的服務(wù)被命令行的 jar 包替換掉了,啟動之后還是正常的。
docker stop mycentos
docker rm -f mycentos
docker run -d -p 8080:8080 --name mycentos mycentos:0.4 docker_testtwo.jar
實戰(zhàn)生成 tomcat 鏡像
????????第一步、編寫 xhf_dockerfile 文件,tomcat 的下載地址在這,如下所示:
FROM centos:7
MAINTAINER xhf<1982392926@qq.com>
ADD jdk-8u371-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.33.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_371
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.33
ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tailf /usr/local/apache-tomcat-9.0.33/logs/catalina.out
????????第二步、構(gòu)建和啟動,命令如下:
docker build -f xhf_dockerfile -t mytomcat:0.1 .
docker run -d -p 8080:8080 --name mytomcat -v /usr/local/tomcat/test:/usr/local/apache-tomcat-9.0.33/webapps/test -v /usr/local/tomcat/logs:/usr/local/apache-tomcat-9.0.33/logs mytomcat:0.1
????????第三步、新建 web.xml 和 index.jsp,內(nèi)容如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
</web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>youngj</title>
</head>
<body>
Hello World!<br/>
<%
System.out.println("你的 IP 地址 " + request.getRemoteAddr());
%>
</body>
</html>
?第四步、測試,在瀏覽器輸入?http://localhost:8080/test/index.jsp,內(nèi)容如下所示:
文章來源:http://www.zghlxwxcb.cn/news/detail-725982.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-725982.html
到了這里,關(guān)于Docker定制鏡像(Dockerfile)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!