08-Docker創建鏡像

一、Dockerfile創建自定義Docker鏡像

1、Dockerfile簡介

1.1 Dockerfile概念

????Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建之后也不會被改變。

????鏡像的定制實際上就是定制每一層所添加的配置、文件。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定制鏡像,那么之前提及的無法重復的問題、鏡像構建透明性的問題、體積的問題就都會解決。這個腳本就是 Dockerfile。

????Dockerfile 是一個文本文件,其內包含了一條條的指令(Instruction),每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。有了 Dockerfile,當我們需要定制自己額外的需求時,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻煩。

1.2 關系圖

????通過上圖可以看出使用 Dockerfile 定義鏡像,運行鏡像啟動容器。

1.3 Dockerfile作用

????1、對于開發人員:可以為開發團隊提供一個完全一致的開發環境;

????2、對于測試人員:可以直接拿開發時所構建的鏡像或者通過Dockerfile文件構建一個新的鏡像開始工作了;

????3、對于運維人員:在部署時,可以實現應用的無縫移植。

1.4 Dockerfile組成

????DockerFile分為四部分組成:基礎鏡像信息、維護者信息、鏡像操作指令和容器啟動時執行指令。一開始必須要指明所基于的鏡像名稱,接下來一般會說明維護者信息;后面則是鏡像操作指令,例如 RUN 指令。每執行一條RUN 指令,鏡像添加新的一層,并提交;最后是 CMD 指令,來指明運行容器時的操作命令。

1.5 Dockerfile常用命令

1.6 構建鏡像

????docker build 命令會根據Dockerfile 文件及上下文構建新 Docker 鏡像。構建上下文是指 Dockerfile 所在的本地路徑或一個URL(Git倉庫地址)。構建上下文環境會被遞歸處理,所以構建所指定的路徑還包括了子目錄,而URL還包括了其中指定的子模塊。

????將當前目錄做為構建上下文時,可以像下面這樣使用docker build命令構建鏡像:

????說明:構建會在 Docker 后臺守護進程(daemon)中執行,而不是CLI中。構建前,構建進程會將全部內容(遞歸)發送到守護進程。大多情況下,應該將一個空目錄作為構建上下文環境,并將 Dockerfile 文件放在該目錄下。

????在構建上下文中使用的 Dockerfile 文件,是一個構建指令文件。為了提高構建性能,可以通過.dockerignore文件排除上下文目錄下不需要的文件和目錄。

????在 Docker 構建鏡像的第一步,docker CLI 會先在上下文目錄中尋找.dockerignore文件,根據.dockerignore?文件排除上下文目錄中的部分文件和目錄,然后把剩下的文件和目錄傳遞給 Docker 服務。

????Dockerfile一般位于構建上下文的根目錄下,也可以通過-f指定該文件的位置:

????構建時,還可以通過-t參數指定構建成鏡像的倉庫、標簽。

????例如:倉庫:標簽?

1.7 鏡像標簽

????如果存在多個倉庫下,或使用多個鏡像標簽,就可以使用多個-t參數:

????在 Docker 守護進程執行 Dockerfile 中的指令前,首先會對Dockerfile 進行語法檢查,有語法錯誤時會返回:

1.8 緩存

????Docker 守護進程會一條一條的執行Dockerfile 中的指令,而且會在每一步提交并生成一個新鏡像,最后會輸出最終鏡像的ID。生成完成后,Docker 守護進程會自動清理你發送的上下文。

????Dockerfile文件中的每條指令會被獨立執行,并會創建一個新鏡像,RUN cd /tmp等命令不會對下條指令產生影響。

????Docker 會重用已生成的中間鏡像,以加速docker build的構建速度。以下是一個使用了緩存鏡像的執行過程:

????構建緩存僅會使用本地父生成鏈上的鏡像,如果不想使用本地緩存的鏡像,也可以通過--cache-from指定緩存。指定后將不再使用本地生成的鏡像鏈,而是從鏡像倉庫中下載。

1.9 尋找緩存的邏輯

????Docker尋找緩存的邏輯其實就是樹型結構根據 Dockerfile 指令遍歷子節點的過程。下圖可以說明這個邏輯。

????大部分指令可以根據上述邏輯去尋找緩存,除了 ADD 和 COPY 。這兩個指令會復制文件內容到鏡像內,除了指令相同以外,Docker 還會檢查每個文件內容校驗(不包括最后修改時間和最后訪問時間),如果校驗不一致,則不會使用緩存。

????除了這兩個命令,Docker并不會去檢查容器內的文件內容,比如?RUN apt-get -y update,每次執行時文件可能都不一樣,但是Docker認為命令一致,會繼續使用緩存。這樣一來,以后構建時都不會再重新運行apt-get -y update。

????如果Docker沒有找到當前指令的緩存,則會構建一個新的鏡像,并且之后的所有指令都不會再去尋找緩存。

2、 Dockerfile官方實踐

2.1 Dockerfile官方資料

Docker與PostgreSQL

調研發現,目前Docker 官方Hub已經提供PostgreSQL各個版本的鏡像。

網址:https://hub.docker.com/_/postgres/

獲取方式:docker pull postgres

支持的PostgreSQL版本有:

10.4,?10,?latest?(10/Dockerfile)

10.4-alpine,?10-alpine,?alpine?(10/alpine/Dockerfile)

9.6.9,?9.6,?9?(9.6/Dockerfile)

9.6.9-alpine,?9.6-alpine,?9-alpine?(9.6/alpine/Dockerfile)

9.5.13,?9.5?(9.5/Dockerfile)

9.5.13-alpine,?9.5-alpine?(9.5/alpine/Dockerfile)

9.4.18,?9.4?(9.4/Dockerfile)

9.4.18-alpine,?9.4-alpine?(9.4/alpine/Dockerfile)

9.3.23,?9.3?(9.3/Dockerfile)

9.3.23-alpine,?9.3-alpine?(9.3/alpine/Dockerfile)

問題提交地址:

https://github.com/docker-library/postgres/issues

目前由PostgreSQL

Docker社區維護,地址https://github.com/docker-library/postgres

支持的架構有:

IBM z Systems (s390x):https://hub.docker.com/u/s390x/

ARMv7 32-bit (arm32v7):https://hub.docker.com/u/arm32v7/

Windows x86-64 (windows-amd64):https://hub.docker.com/u/winamd64/

Linux x86-64 (amd64):https://hub.docker.com/u/amd64/

Other architectures built by official images:(butnotofficially supported by Docker, Inc.)

IBM POWER8 (ppc64le):https://hub.docker.com/u/ppc64le/

x86/i686 (i386):https://hub.docker.com/u/i386/

ARMv8 64-bit (arm64v8):https://hub.docker.com/u/arm64v8/

ARMv6 32-bit (arm32v6):https://hub.docker.com/u/arm32v6/(RaspberryPi 1, Raspberry Pi Zero)

ARMv5 32-bit (arm32v5):https://hub.docker.com/u/arm32v5/

2.2對官網10.4,?10,?latest?(10/Dockerfile)的理解

?????對官網10.4,?10,?latest?(10/Dockerfile)的理解這部分內容如下所示:

FROM debian:stretch-slim

# set -ex 其中 e 代表 若指令傳回值不等于0(指令成功返回0,不成功返回值不是0),立刻退出shell? ; x 代表 執行指令后,會先顯示該指令及所下的參數

RUN set -ex; \

# command -v gpg 是用來判斷是否存在gpg這個命令(這個命令是用來對密鑰進行操作的,生成密鑰、列出密鑰等),

# ! 代表取反,也就是說,這個判斷條件在當? gpg這個命令不存在的時候成立,會執行then后面的內容

if ! command -v gpg > /dev/null; then \

# apt-get 是 Ubuntu中安裝包的命令,等同于? centos中的? yum, 這里? 就相當于先更新所有本機器上的包

apt-get update; \

# no-install-recommends參數用來避免安裝非必須的文件,從而最小化安裝所需要的包,下面安裝的包是和密鑰gpg命令相關的包

apt-get install -y --no-install-recommends \

gnupg \

dirmngr \

; \

# 刪除下載的安裝包

rm -rf /var/lib/apt/lists/*; \

fi

# explicitly set user/group IDs

# 創建postgres用戶組,組id設置為999,在用戶組postgres中創建用戶postgres,用戶id設置為999

RUN groupadd -r postgres --gid=999 && useradd -r -g postgres --uid=999 postgres

# grab gosu for easy step-down from root

# 設置全局變量 相當于shell中的? GOSU_VERSION=1.10

ENV GOSU_VERSION 1.10

# 等同于第四行, x 代表 執行指令后,會先顯示該指令及所下的參數

RUN set -x \

# 安裝 ca-certificates 證書相關的包 和? wget 從url下載文件的包,安裝完刪除安裝包

&& apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \

# 從github 下載gosu , https://github.com/tianon/gosu/ 這個是gosu這個項目的網站,其功能是為了替代su和sudo,因為su和sudo在執行的時候需要TTY和信號轉發的動作。

# 具體詳情可以查看 https://github.com/tianon/gosu/ 上的功能介紹

# wget -O 保存下載文件的路徑? 下載地址

&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \

&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \

# 設置環境變量 GUNPGHOME , 這個是臨時設置的,如果系統重啟后,這個環境變量就會失效 (如果想要設置永久的環境變量需要寫入到文件里)

&& export GNUPGHOME="$(mktemp -d)" \

# 這是配置了公鑰,原文說是為了驗證下載

&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \

# 驗證下載的版本

&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \

# 刪除臨時目錄和密鑰文件

&& rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \

# 給命令? /usr/local/bin/gosu 設置可執行權限

&& chmod +x /usr/local/bin/gosu \

# 切換到nobody用戶

&& gosu nobody true \

# 刪除剛剛安裝的包 ca-certificates 和 wget? ,? purge 是卸載并清除軟件包的配置,auto-remove是卸載所有自動安裝且不再使用的軟件包

&& apt-get purge -y --auto-remove ca-certificates wget

# make the "en_US.UTF-8" locale so postgres will be utf-8 enabled by default

# set命令? e 代表指令返回值不為0則退出shell;u當執行時使用到未定義過的變量,顯示錯誤信息;x執行指令后,會先顯示該指令及所下的參數

RUN set -eux; \

# 判斷是否有? /etc/dpkg/dpkg.cfg.d/docker 這個文件,如果有則執行后面的語句

if [ -f /etc/dpkg/dpkg.cfg.d/docker ]; then \

# if this file exists, we're likely in "debian:xxx-slim", and locales are thus being excluded so we need to remove that exclusion (since we need locales)

# grep是抓取命令, -q代表不輸出結果,這個意思其實是判斷? /etc/dpkg/dpkg.cfg.d/docker 文件中是否存在? '/usr/share/locale' 這個內容,

# 可以用? echo $? 來輸出返回值,如果存在則返回值是0,如果不存在返回是1,又由于最開頭設置了? set -eux,所以如果不存在,則后續指令直接退出

grep -q '/usr/share/locale' /etc/dpkg/dpkg.cfg.d/docker; \

# 刪除 /etc/dpkg/dpkg.cfg.d/docker 文件中存在? /usr/share/locale 這個內容的一行

sed -ri '/\/usr\/share\/locale/d' /etc/dpkg/dpkg.cfg.d/docker; \

# !代表取反,這個就是驗證是否刪除完成

! grep -q '/usr/share/locale' /etc/dpkg/dpkg.cfg.d/docker; \

fi; \

# 更新,升級。安裝locales包,刪除下載的安裝包

apt-get update; apt-get install -y locales; rm -rf /var/lib/apt/lists/*; \

# -i 設置語言環境, -c 代表即使報錯,仍強制執行, -f 設置字符符號的語言?

localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8

# 設置環境變量,設置語言為英語,字符集為utf-8

ENV LANG en_US.utf8

# 創建目錄 /docker-entrypoint-initdb.d

RUN mkdir /docker-entrypoint-initdb.d

# set命令? e 代表指令返回值不為0則退出shell;x執行指令后,會先顯示該指令及所下的參數

RUN set -ex; \

# pub? 4096R/ACCC4CF8 2011-10-13 [expires: 2019-07-02]

#? ? ? Key fingerprint = B97B 0AFC AA1A 47F0 44F2? 44A0 7FCC 7D46 ACCC 4CF8

# uid? ? ? ? ? ? ? ? ? PostgreSQL Debian Repository

key='B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8'; \

export GNUPGHOME="$(mktemp -d)"; \

gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \

gpg --export "$key" > /etc/apt/trusted.gpg.d/postgres.gpg; \

rm -rf "$GNUPGHOME"; \

apt-key list

ENV PG_MAJOR 10

ENV PG_VERSION 10.4-1.pgdg90+1

RUN set -ex; \

\

# 獲取系統內核位數

dpkgArch="$(dpkg --print-architecture)"; \

case "$dpkgArch" in \

amd64|i386|ppc64el) \

# arches officialy built by upstream

# 如果輸出結果在? amd64, i386, ppc64el的話,執行后面的命令

echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main $PG_MAJOR" > /etc/apt/sources.list.d/pgdg.list; \

apt-get update; \

;; \

*) \

# we're on an architecture upstream doesn't officially build for

# let's build binaries from their published source packages

# 如果版本不在 amd64, i386, ppc64el 中的話,執行下面命令

echo "deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main $PG_MAJOR" > /etc/apt/sources.list.d/pgdg.list; \

\

tempDir="$(mktemp -d)"; \

cd "$tempDir"; \

\

savedAptMark="$(apt-mark showmanual)"; \

\

# build .deb files from upstream's source packages (which are verified by apt-get)

apt-get update; \

apt-get build-dep -y \

postgresql-common pgdg-keyring \

"postgresql-$PG_MAJOR=$PG_VERSION" \

; \

DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \

apt-get source --compile \

postgresql-common pgdg-keyring \

"postgresql-$PG_MAJOR=$PG_VERSION" \

; \

# we don't remove APT lists here because they get re-downloaded and removed later

\

# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies

# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies)

apt-mark showmanual | xargs apt-mark auto > /dev/null; \

apt-mark manual $savedAptMark; \

\

# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be)

ls -lAFh; \

dpkg-scanpackages . > Packages; \

grep '^Package: ' Packages; \

echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list; \

# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes")

#? Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied)

#? ...

#? E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages? Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied)

apt-get -o Acquire::GzipIndexes=false update; \

;; \

esac; \

\

# 安裝postgresql-common包

apt-get install -y postgresql-common; \

# 修改 /etc/postgresql-common/createcluster.conf 文件的參數

sed -ri 's/#(create_main_cluster) .*$/\1 = false/' /etc/postgresql-common/createcluster.conf; \

# 安裝 postgresql

apt-get install -y \

"postgresql-$PG_MAJOR=$PG_VERSION" \

; \

\

rm -rf /var/lib/apt/lists/*; \

\

if [ -n "$tempDir" ]; then \

# if we have leftovers from building, let's purge them (including extra, unnecessary build deps)

apt-get purge -y --auto-remove; \

rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \

fi

# make the sample config easier to munge (and "correct by default")

# 配置默認的配置文件? postgresql.conf

# mv -v 這里表示移動postgresql.conf.sample 到/usr/share/postgresql/文件夾下, -v 表示顯示命令執行的信息

RUN mv -v "/usr/share/postgresql/$PG_MAJOR/postgresql.conf.sample" /usr/share/postgresql/ \

# ln -sv , -s 代表設置軟連接,-v 代表顯示詳細的處理過程

&& ln -sv ../postgresql.conf.sample "/usr/share/postgresql/$PG_MAJOR/" \

# 修改postgresql.conf.sample中的 listen_addresses參數

&& sed -ri "s!^#?(listen_addresses)\s*=\s*\S+.*!\1 = '*'!" /usr/share/postgresql/postgresql.conf.sample

# 創建 /var/run/postgresql目錄,將目錄的所屬用戶和用戶組設置為postgres,將目錄賦予可執行權限

RUN mkdir -p /var/run/postgresql && chown -R postgres:postgres /var/run/postgresql && chmod 2777 /var/run/postgresql

# 設置將postgresql目錄設置到環境變量中

ENV PATH $PATH:/usr/lib/postgresql/$PG_MAJOR/bin

ENV PGDATA /var/lib/postgresql/data

# 創建目錄環境變量中使用到的目錄,并賦予777權限

RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)

# 掛載目錄為? /var/lib/postgresql/data

VOLUME /var/lib/postgresql/data

# 將docker-entrypoint.sh 腳本考入到容器內的/usr/local/bin 目錄下

COPY docker-entrypoint.sh /usr/local/bin/

# 將 /usr/local/bin/docker-entrypoint.sh 這個腳本軟連到 / 目錄下

RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat

# ENTRYPOINT這個命令需要在? docker run啟動運行的時候執行,類似于開機啟動腳本

ENTRYPOINT ["docker-entrypoint.sh"]

# 容器內部端口地址為5432

EXPOSE 5432

# 開機啟動的執行命令

CMD ["postgres"]

3 Dockerfile實踐

3.1 以Postgressql10.3為例

當前安裝的流程是源碼安裝

如果要用yum安裝的話。區別如下:

????1.沒辦法將安裝文件指定目錄

????2.yum會自己將依賴包進行安裝,不再需要手動安裝

????3.yum安裝完成后會自動配置好環境變量,不再需要手動配置

????4.yum安裝完成后會自動創建出默認的初始化的庫

二、手工集成自定義Docker鏡像

1、Docker集成HGDB

1.1部署流程圖

1.2具體操作

1)啟動Docker服務

2)下載centos鏡像

3)用centos鏡像創建容器

4)進入容器

5)安裝HGDB

6)將容器打包成鏡像

7)初始化宿主機數據庫

8)啟動鏡像映射至宿主機5458端口,并掛載本地磁盤節點到容器上

9)進入到容器后,啟動應用

10)登錄數據庫

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • docker基本概念 1. Image Definition 鏡像 Image 就是一堆只讀層 read-only...
    慢清塵閱讀 8,795評論 1 21
  • 實例來源:tofar 摘錄來源:Docker — 從入門到實踐 歡迎大家添加自己的實例 (email: yun_...
    molscar閱讀 433評論 1 1
  • 五、Docker 端口映射 無論如何,這些 ip 是基于本地系統的并且容器的端口非本地主機是訪問不到的。此外,除了...
    R_X閱讀 1,787評論 0 7
  • 在前面兩節我們學習了如何安裝以及簡單的運行管理docker容器,在本節我們將會更多的探討關于docker鏡像的知識...
    井底蛙蛙呱呱呱閱讀 4,110評論 0 5
  • Docker docker常用命令: sudo docker images // 查看本機已有的鏡像 docker...
    neo_ng閱讀 613評論 0 1