一、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-alpine,?9.5-alpine?(9.5/alpine/Dockerfile)
9.4.18-alpine,?9.4-alpine?(9.4/alpine/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)登錄數據庫