<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于Dockerfile構(gòu)建容器鏡像的最佳實(shí)踐

          共 16466字,需瀏覽 33分鐘

           ·

          2021-11-30 04:29

          目錄

          • 1、背景概述

          • 2、為什么鏡像會(huì)這么大

            • 2.1 基礎(chǔ)鏡像過(guò)大

            • 2.2 基礎(chǔ)鏡像過(guò)大,而且找不到了

            • 2.3 .git 目錄(非必要目錄)

            • 2.4 Dockerfile 本身有其他問(wèn)題

          • 3、Dockerfile 如何優(yōu)化

            • 3.1 從哪里入手

            • 3.2 方案

            • 3.3 樣例

          • 4、除了這些優(yōu)化還可以做什么

            • 4.1 設(shè)置字符集

            • 4.2 時(shí)區(qū)校正

            • 4.3 進(jìn)程管理

            • 4.4 降權(quán)啟動(dòng)

            • 4.5 底層庫(kù)依賴

          • 5、小結(jié)


          1、背景概述

          容器鏡像是容器化落地轉(zhuǎn)型的第一步,總結(jié)幾點(diǎn)需要做鏡像優(yōu)化的原因

          隨著應(yīng)用容器化部署的大規(guī)模遷移以及版本迭代的加快,優(yōu)化基礎(chǔ)設(shè)施之docker鏡像主要有以下目的

          • 縮短部署時(shí)的鏡像下載時(shí)間

          • 提升安全性,減少可供攻擊的目標(biāo)

          • 減少故障恢復(fù)時(shí)間

          • 節(jié)省存儲(chǔ)開銷

          2、為什么鏡像會(huì)這么大

          這里簡(jiǎn)要分析了幾個(gè)典型的Repo,總結(jié)了現(xiàn)有Docker鏡像較大的幾個(gè)原因

          2.1 基礎(chǔ)鏡像過(guò)大

          舉例:倉(cāng)庫(kù)A,制作出來(lái)的鏡像大小9.67GB

          用到的基礎(chǔ)鏡像:鏡像大小8.72GB

          逆向分析了一下,為啥基礎(chǔ)鏡像還這么大?結(jié)果就不用多說(shuō)了 0.0

          2.2 基礎(chǔ)鏡像過(guò)大,而且找不到了

          舉例:倉(cāng)庫(kù)B,制作出來(lái)的鏡像大小22.7GB

          用到的基礎(chǔ)鏡像:404 not found,沒錯(cuò),找不到了 0.0

          2.3 .git 目錄(非必要目錄)

          這個(gè)問(wèn)題更多內(nèi)容可以參考我之前的文章?Git目錄為什么這么大?[1]

          舉例:倉(cāng)庫(kù)C,代碼大小795MB

          其中.git目錄大小225MBdockerfile中的指令如下(全部添加到了鏡像中)

          ADD?.?/app/startapp/

          其中還包含了d目錄大小約300MB,是否需要使用不得而知,但目測(cè)不需要使用,僅為測(cè)試數(shù)據(jù)

          d
          ├──?[?503]??test_421.json
          ├──?[?483]??test_havalB9.json
          ...
          ├──?[?484]??test_144.json
          ├──?[?104]??.gitmodules
          ├──?[?122]??.idea
          ├──?[???0]??__init__.py
          ├──?[?11M]??164103.zip
          ├──?[108M]??test_180753.csv
          ├──?[?68M]??test_180753.txt
          ...
          └──?[?335]??README.md

          以上其實(shí)都不需要提交到鏡像中制作成鏡像

          2.4 Dockerfile 本身有其他問(wèn)題

          這個(gè)原因不言而喻,不是專業(yè)的人寫的Dockerfile可能都有一定的優(yōu)化空間,只是暫時(shí)沒關(guān)注這些細(xì)節(jié)而已

          例如,放任各路repo研發(fā)自行寫Dockerfile,沒有一定的標(biāo)準(zhǔn),前期可能無(wú)所謂,到后期問(wèn)題就慢慢浮現(xiàn)了

          正所謂《能用就行》~

          3、Dockerfile 如何優(yōu)化

          3.1 從哪里入手

          優(yōu)化docker鏡像應(yīng)該從鏡像分層概念入手

          3.1.1 舉個(gè)栗子

          一個(gè)實(shí)際的例子

          nginx:alpine 鏡像 23.2MB

          #?docker?history?nginx:alpine
          IMAGE??????????CREATED???????CREATED?BY??????????????????????????????????????SIZE??????COMMENT
          b46db85084b8???9?days?ago????/bin/sh?-c?#(nop)??CMD?["nginx"?"-g"?"daemon…???0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??STOPSIGNAL?SIGQUIT???????????0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??EXPOSE?80????????????????????0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??ENTRYPOINT?["/docker-entr…???0B
          ??????9?days?ago????/bin/sh?-c?#(nop)?COPY?file:09a214a3e07c919a…???4.61kB
          ??????9?days?ago????/bin/sh?-c?#(nop)?COPY?file:0fd5fca330dcd6a7…???1.04kB
          ??????9?days?ago????/bin/sh?-c?#(nop)?COPY?file:0b866ff3fc1ef5b0…???1.96kB
          ??????9?days?ago????/bin/sh?-c?#(nop)?COPY?file:65504f71f5855ca0…???1.2kB
          ??????9?days?ago????/bin/sh?-c?set?-x?????&&?addgroup?-g?101?-S?…???17.6MB
          ??????9?days?ago????/bin/sh?-c?#(nop)??ENV?PKG_RELEASE=1????????????0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??ENV?NJS_VERSION=0.7.0????????0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??ENV?NGINX_VERSION=1.21.4?????0B
          ??????9?days?ago????/bin/sh?-c?#(nop)??LABEL?maintainer=NGINX?Do…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??CMD?["/bin/sh"]??????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)?ADD?file:762c899ec0505d1a3…???5.61MB

          python:alpine 鏡像 45.5MB

          #?docker?history?python:alpine
          IMAGE??????????CREATED???????CREATED?BY??????????????????????????????????????SIZE??????COMMENT
          382a63bb2f25???10?days?ago???/bin/sh?-c?#(nop)??CMD?["python3"]??????????????0B
          ??????10?days?ago???/bin/sh?-c?set?-ex;???wget?-O?get-pip.py?"$P…???8.31MB
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PYTHON_GET_PIP_SHA256…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PYTHON_GET_PIP_URL=ht…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PYTHON_SETUPTOOLS_VER…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PYTHON_PIP_VERSION=21…???0B
          ??????10?days?ago???/bin/sh?-c?cd?/usr/local/bin??&&?ln?-s?idle3…???32B
          ??????10?days?ago???/bin/sh?-c?set?-ex??&&?apk?add?--no-cache?--…???29.8MB
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PYTHON_VERSION=3.10.0????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?GPG_KEY=A035C8C19219B…???0B
          ??????10?days?ago???/bin/sh?-c?set?-eux;??apk?add?--no-cache???c…???1.82MB
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?LANG=C.UTF-8?????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PATH=/usr/local/bin:/…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??CMD?["/bin/sh"]??????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)?ADD?file:762c899ec0505d1a3…???5.61MB

          實(shí)際存儲(chǔ)

          #?docker?inspect?nginx:alpine|?jq?'.[0]|{GraphDriver}'
          {
          ??"GraphDriver":?{
          ????"Data":?{
          ??????"LowerDir":?"/data/docker-overlay2/overlay2/3d.../diff:/data/docker-overlay2/overlay2/ae.../diff:/data/docker-overlay2/overlay2/ea.../diff:/data/docker-overlay2/overlay2/29.../diff:/data/docker-overlay2/overlay2/5e.../diff",
          ??????"MergedDir":?"/data/docker-overlay2/overlay2/b7.../merged",
          ??????"UpperDir":?"/data/docker-overlay2/overlay2/b7.../diff",
          ??????"WorkDir":?"/data/docker-overlay2/overlay2/b7.../work"
          ????},
          ????"Name":?"overlay2"
          ??}
          }

          分層概念的描述

          鏡像解決了應(yīng)用運(yùn)行及環(huán)境的打包問(wèn)題,實(shí)際應(yīng)用中應(yīng)用都是基于同一個(gè)rootfs來(lái)打包和迭代的,但并不是每個(gè)rootfs都會(huì)多份,實(shí)際上docker利用了存儲(chǔ)驅(qū)動(dòng)AUFSdevicemapperoverlayoverlay2的存儲(chǔ)技術(shù)實(shí)現(xiàn)了分層

          例如上面查看一個(gè)docker鏡像會(huì)發(fā)現(xiàn)這些層

          • LowerDir:鏡像層

          • MergedDir:整合了 lower 層和 upper 讀寫層顯示出來(lái)的視圖

          • UpperDir:讀寫層

          • WorkDir:中間層,對(duì) Upper 層的寫入,先寫入 WorkDir,再移入 UpperDir

          3.1.2 Copy on write

          當(dāng)Docker第一次啟動(dòng)一個(gè)容器時(shí),初始的讀寫層是空的,當(dāng)文件系統(tǒng)發(fā)生變化時(shí),這些變化都會(huì)應(yīng)用到這一層之上。比如,如果想修改一個(gè)文件,這個(gè)文件首先會(huì)從該讀寫層下面的只讀層復(fù)制到該讀寫層。由此,該文件的只讀版本依然存在于只讀層,只是被讀寫層的該文件副本所隱藏,該機(jī)制則被稱之為寫時(shí)復(fù)制

          3.1.3 UnionFS

          把多個(gè)目錄(也叫分支)內(nèi)容聯(lián)合掛載到同一個(gè)目錄下,而目錄的物理位置是分開的

          一個(gè)直觀的效果,第一次拉取一個(gè)nginx:1.15版本鏡像,再次拉取nginx:1.16鏡像,速度要快很多

          3.2 方案

          了解了鏡像大小的主要構(gòu)成之后,就很容易知道從哪些方向入手減少鏡像大小了

          3.2.1 減少鏡像層數(shù)

          鏡像層數(shù)的增加,對(duì)Dockerfile來(lái)說(shuō)主要在于RUN指令出現(xiàn)的次數(shù),因此,合并RUN指令可以大大減少鏡像層數(shù)

          舉個(gè)栗子:

          合并前,三層

          RUN?apk?add?tzdata
          RUN?cp?/usr/share/zoneinfo/Asia/Shanghai?/etc/localtime
          RUN?echo?"Asia/Shanghai"?>?/etc/timezone

          合并后,一層

          RUN?apk?add?tzdata?\
          ????&&?cp?/usr/share/zoneinfo/Asia/Shanghai?/etc/localtime?\
          ????&&?echo?"Asia/Shanghai"?>?/etc/timezone

          3.2.2 減少每層鏡像大小

          3.2.2.1 選用更小的基礎(chǔ)鏡像
          • scratch:空鏡像,又叫鏡像之父!任何鏡像都需要有一個(gè)基礎(chǔ)鏡像,那么問(wèn)題來(lái)了,就好比是先有雞還是先有蛋的問(wèn)題,基礎(chǔ)鏡像的“祖宗”是什么呢?能不能在構(gòu)建時(shí)不以任何鏡像為基礎(chǔ)呢?答案是肯定的,可以選用scratch,具體就不展開了,可以參考:baseimages[2],使用scratch鏡像的例子pause
          • busybox:對(duì)比scratch,多了常用的linux工具等
          • alpine:多了包管理工具apk
          3.3.2.2 多階段構(gòu)建

          多階段構(gòu)建非常適用于編譯性語(yǔ)言,簡(jiǎn)單來(lái)說(shuō)就是允許一個(gè)Dockerfile中出現(xiàn)多條FROM指令,只有最后一條FROM指令中指定的基礎(chǔ)鏡像作為本次構(gòu)建鏡像的基礎(chǔ)鏡像,其它的階段都可以認(rèn)為是只為中間步驟

          FROM … AS …COPY --from組合使用

          例如java鏡像,鏡像大小812MB

          FROM?centos?AS?jdk
          COPY?jdk-8u231-linux-x64.tar.gz?/usr/local/src
          RUN?cd?/usr/local/src?&&?\
          ????tar?-xzvf?jdk-8u231-linux-x64.tar.gz?-C?/usr/local

          使用多階段構(gòu)建,鏡像大小618MB

          FROM?centos?AS?jdk
          COPY?jdk-8u231-linux-x64.tar.gz?/usr/local/src
          RUN?cd?/usr/local/src?&&?\
          ????tar?-xzvf?jdk-8u231-linux-x64.tar.gz?-C?/usr/local


          FROM?centos
          COPY?--from=jdk?/usr/local/jdk1.8.0_231?/usr/local
          3.3.2.3 忽略文件

          構(gòu)建上下文build context,“上下文” 意為和現(xiàn)在這個(gè)工作相關(guān)的周圍環(huán)境

          docker build時(shí)當(dāng)前的工作目錄,不管構(gòu)建時(shí)有沒有用到當(dāng)前目錄下的某些文件及目錄,默認(rèn)情況下這個(gè)上下文中的文件及目錄都會(huì)作為構(gòu)建上下文內(nèi)容發(fā)送給Docker Daemon

          當(dāng)docker build開始執(zhí)行時(shí),控制臺(tái)會(huì)輸出Sending build context to Docker daemon xxxMB,這就表示將當(dāng)前工作目錄下的文件及目錄都作為了構(gòu)建上下文

          前面提到可以在RUN指令中添加--no-cache不使用緩存,同樣也可以在執(zhí)行docker build命令時(shí)添加該指令以在鏡像構(gòu)建時(shí)不使用緩存

          構(gòu)建上下文中,使用.dockerignore 文件在構(gòu)建時(shí)就可以避免將本地模塊以及調(diào)試日志被拷貝進(jìn)入到Docker鏡像中,這和git版本控制的.gitignore很類似

          3.3.2.4 遠(yuǎn)程下載

          使用遠(yuǎn)程下載代替ADD可以減少鏡像大小

          RUN?curl?-s?http://192.168.1.1/repository/tools/jdk-8u241-linux-x64.tar.gz?|?tar?-xC?/opt/
          3.3.2.5 拆分 COPY

          例如一個(gè)COPY指令的目錄下A4個(gè)子目錄AA/BB/CC/DDCOPY,但常變化的只有一個(gè) BB

          這個(gè)時(shí)候拆分COPY會(huì)更快

          COPY?A/AA?/app/A/AA
          COPY?A/BB?/app/A/BB
          COPY?A/CC?/app/A/CC
          COPY?A/DD?/app/A/DD
          3.3.2.6 構(gòu)建時(shí)掛載

          構(gòu)建時(shí)掛載(擴(kuò)展功能[3]

          配置

          • 修改 docker 啟動(dòng)參數(shù),添加--experimental
          • dockerfile 頭部添加# syntax=docker/dockerfile:1.1.1-experimental

          使用

          • 掛載本地 golang 緩存
          #?syntax?=?docker/dockerfile:experimental
          FROM?golang
          ...
          RUN?--mount=type=cache,target=/root/.cache/go-build?go?build?...
          • 掛載 cache 目錄
          #?syntax?=?docker/dockerfile:experimental
          FROM?ubuntu
          RUN?rm?-f?/etc/apt/apt.conf.d/docker-clean;?echo?'Binary::apt::APT::Keep-Downloaded-Packages?"true";'?>?/etc/apt/apt.conf.d/keep-cache
          RUN?--mount=type=cache,target=/var/cache/apt?--mount=type=cache,target=/var/lib/apt?\
          ??apt?update?&&?apt?install?-y?gcc

          • 掛載某些憑據(jù)
          #?syntax?=?docker/dockerfile:experimental
          FROM?python:3
          RUN?pip?install?awscli
          RUN?--mount=type=secret,id=aws,target=/root/.aws/credentials?aws?s3?cp?s3://...?...

          等等

          3.3.2.7 構(gòu)建后清理
          • 刪除壓縮包
          • 清理安裝緩存
            • --no-cache
            • rm -rf /var/lib/apt/lists/*
            • rm -rf /var/cache/yum/*
          3.3.2.8 鏡像壓縮

          exportimport組合進(jìn)行壓縮鏡像(壓縮效果不是很明顯)

          這種方法不好的就是會(huì)丟失一部分鏡像信息

          #?docker?run?-d?--name?nginx?nginx:alpine
          #?docker?export?nginx?|docker?import?-?nginx:alpine2
          sha256:dd6a3cf822ac3c3ad3e7f7b31675cd8cd99a6f80e360996e04da6fc2f3b98cb5
          #?docker?history?nginx:alpine
          IMAGE??????????CREATED???????CREATED?BY??????????????????????????????????????SIZE??????COMMENT
          b46db85084b8???10?days?ago???/bin/sh?-c?#(nop)??CMD?["nginx"?"-g"?"daemon…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??STOPSIGNAL?SIGQUIT???????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??EXPOSE?80????????????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENTRYPOINT?["/docker-entr…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)?COPY?file:09a214a3e07c919a…???4.61kB
          ??????10?days?ago???/bin/sh?-c?#(nop)?COPY?file:0fd5fca330dcd6a7…???1.04kB
          ??????10?days?ago???/bin/sh?-c?#(nop)?COPY?file:0b866ff3fc1ef5b0…???1.96kB
          ??????10?days?ago???/bin/sh?-c?#(nop)?COPY?file:65504f71f5855ca0…???1.2kB
          ??????10?days?ago???/bin/sh?-c?set?-x?????&&?addgroup?-g?101?-S?…???17.6MB
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?PKG_RELEASE=1????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?NJS_VERSION=0.7.0????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??ENV?NGINX_VERSION=1.21.4?????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??LABEL?maintainer=NGINX?Do…???0B
          ??????10?days?ago???/bin/sh?-c?#(nop)??CMD?["/bin/sh"]??????????????0B
          ??????10?days?ago???/bin/sh?-c?#(nop)?ADD?file:762c899ec0505d1a3…???5.61MB
          #?docker?history?nginx:alpine2
          IMAGE??????????CREATED??????????CREATED?BY???SIZE??????COMMENT
          dd6a3cf822ac???40?seconds?ago????????????????23MB??????Imported?from?-
          #?docker?images|grep?nginx
          nginx???????????????????????????????????????????????????????????????????????????????????????????????????????????????alpine2?????????????????????dd6a3cf822ac???54?seconds?ago???23MB
          nginx???????????????????????????????????????????????????????????????????????????????????????????????????????????????alpine??????????????????????b46db85084b8???10?days?ago??????23.2MB

          3.3 樣例

          3.3.1 go 樣例

          樣例一

          kubeadm安裝的k8s集群,kube-apiserver鏡像的Dockerfile是利用bazel編譯工具編譯的

          bazel?build?...
          LABEL?maintainers=Kubernetes?Authors
          LABEL?description=go?based?runner?for?distroless?scenarios
          WORKDIR?/
          COPY?/workspace/go-runner?.?#?buildkit
          ENTRYPOINT?["/go-runner"]
          COPY?file:2e904ea733ba0ded2a99947847de31414a19d83f8495dd8c1fbed3c70bf67a22?in?/usr/local/bin/kube-apiserver

          代碼目錄 28M(包含.git 目錄 20.5M)

          鏡像大小 122MB

          樣例二

          開源編排引擎CadenceDockerfile

          ARG?TARGET=server

          #?Can?be?used?in?case?a?proxy?is?necessary
          ARG?GOPROXY

          #?Build?tcheck?binary
          FROM?golang:1.17-alpine3.13?AS?tcheck

          WORKDIR?/go/src/github.com/uber/tcheck

          COPY?go.*?./
          RUN?go?build?-mod=readonly?-o?/go/bin/tcheck?github.com/uber/tcheck

          #?Build?Cadence?binaries
          FROM?golang:1.17-alpine3.13?AS?builder

          ARG?RELEASE_VERSION

          RUN?apk?add?--update?--no-cache?ca-certificates?make?git?curl?mercurial?unzip

          WORKDIR?/cadence

          #?Making?sure?that?dependency?is?not?touched
          ENV?GOFLAGS="-mod=readonly"

          #?Copy?go?mod?dependencies?and?build?cache
          COPY?go.*?./
          RUN?go?mod?download

          COPY?.?.
          RUN?rm?-fr?.bin?.build

          ENV?CADENCE_RELEASE_VERSION=$RELEASE_VERSION

          #?bypass?codegen,?use?committed?files.??must?be?run?separately,?before?building?things.
          RUN?make?.fake-codegen
          RUN?CGO_ENABLED=0?make?copyright?cadence-cassandra-tool?cadence-sql-tool?cadence?cadence-server?cadence-bench?cadence-canary


          #?Download?dockerize
          FROM?alpine:3.11?AS?dockerize

          RUN?apk?add?--no-cache?openssl

          ENV?DOCKERIZE_VERSION?v0.6.1
          RUN?wget?https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz?\
          ????&&?tar?-C?/usr/local/bin?-xzvf?dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz?\
          ????&&?rm?dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz?\
          ????&&?echo?"****?fix?for?host?id?mapping?error?****"?\
          ????&&?chown?root:root?/usr/local/bin/dockerize



          #?Alpine?base?image
          FROM?alpine:3.11?AS?alpine

          RUN?apk?add?--update?--no-cache?ca-certificates?tzdata?bash?curl

          #?set?up?nsswitch.conf?for?Go's?"netgo"?implementation
          #?https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-424546457
          RUN?test?!?-e?/etc/nsswitch.conf?&&?echo?'hosts:?files?dns'?>?/etc/nsswitch.conf

          SHELL?["/bin/bash",?"-c"]


          #?Cadence?server
          FROM?alpine?AS?cadence-server

          ENV?CADENCE_HOME?/etc/cadence
          RUN?mkdir?-p?/etc/cadence

          COPY?--from=tcheck?/go/bin/tcheck?/usr/local/bin
          COPY?--from=dockerize?/usr/local/bin/dockerize?/usr/local/bin
          COPY?--from=builder?/cadence/cadence-cassandra-tool?/usr/local/bin
          COPY?--from=builder?/cadence/cadence-sql-tool?/usr/local/bin
          COPY?--from=builder?/cadence/cadence?/usr/local/bin
          COPY?--from=builder?/cadence/cadence-server?/usr/local/bin
          COPY?--from=builder?/cadence/schema?/etc/cadence/schema

          COPY?docker/entrypoint.sh?/docker-entrypoint.sh
          COPY?config/dynamicconfig?/etc/cadence/config/dynamicconfig
          COPY?config/credentials?/etc/cadence/config/credentials
          COPY?docker/config_template.yaml?/etc/cadence/config
          COPY?docker/start-cadence.sh?/start-cadence.sh

          WORKDIR?/etc/cadence

          ENV?SERVICES="history,matching,frontend,worker"

          EXPOSE?7933?7934?7935?7939
          ENTRYPOINT?["/docker-entrypoint.sh"]
          CMD?/start-cadence.sh


          #?All-in-one?Cadence?server
          FROM?cadence-server?AS?cadence-auto-setup

          RUN?apk?add?--update?--no-cache?ca-certificates?py-pip?mysql-client
          RUN?pip?install?cqlsh

          COPY?docker/start.sh?/start.sh

          CMD?/start.sh


          #?Cadence?CLI
          FROM?alpine?AS?cadence-cli

          COPY?--from=tcheck?/go/bin/tcheck?/usr/local/bin
          COPY?--from=builder?/cadence/cadence?/usr/local/bin

          ENTRYPOINT?["cadence"]

          #?Cadence?Canary
          FROM?alpine?AS?cadence-canary

          COPY?--from=builder?/cadence/cadence-canary?/usr/local/bin
          COPY?--from=builder?/cadence/cadence?/usr/local/bin

          CMD?["/usr/local/bin/cadence-canary",?"--root",?"/etc/cadence-canary",?"start"]

          #?Cadence?Bench
          FROM?alpine?AS?cadence-bench

          COPY?--from=builder?/cadence/cadence-bench?/usr/local/bin
          COPY?--from=builder?/cadence/cadence?/usr/local/bin

          CMD?["/usr/local/bin/cadence-bench",?"--root",?"/etc/cadence-bench",?"start"]

          #?Final?image
          FROM?cadence-${TARGET}

          代碼目錄 85.4M(包含.git 目錄 57.7M)

          鏡像大小 135.69MB

          3.3.2 py 樣例

          FROM?python:3.4

          RUN?apt-get?update?\
          ????&&?apt-get?install?-y?--no-install-recommends?\
          ????????postgresql-client?\
          ????&&?rm?-rf?/var/lib/apt/lists/*


          WORKDIR?/usr/src/app
          COPY?requirements.txt?./
          RUN?pip?install?-r?requirements.txt
          COPY?.?.

          EXPOSE?8000
          CMD?["python",?"manage.py",?"runserver",?"0.0.0.0:8000"]

          代碼目錄 275M(包含.git 目錄 222M)

          鏡像大小 436MB

          4、除了這些優(yōu)化還可以做什么

          4.1 設(shè)置字符集

          Dockerfile中設(shè)置通用的字符集

          #?Set?lang
          ENV?LANG?"en_US.UTF-8"

          4.2 時(shí)區(qū)校正

          這個(gè)問(wèn)題更多內(nèi)容可以參考我之前的文章?k8s環(huán)境下處理容器時(shí)間問(wèn)題的多種姿勢(shì)?[4]

          Dockerfile中設(shè)置通用的時(shí)區(qū)

          #?Set?timezone
          RUN?ln?-sf?/usr/share/zoneinfo/Asia/Shanghai?/etc/localtime?\
          ???&&?echo?"Asia/Shanghai"?>?/etc/timezone

          4.3 進(jìn)程管理

          docker容器運(yùn)行時(shí),默認(rèn)會(huì)以Dockerfile中的ENTRYPOINTCMD作為PID1的主進(jìn)程,這個(gè)進(jìn)程存在的目的,通俗來(lái)說(shuō)需要做的就是將容器"夯住",一旦這個(gè)進(jìn)程不存在了,那么容器就會(huì)退出

          除此之外,這個(gè)主進(jìn)程還有一個(gè)重要的作用就是管理“僵尸進(jìn)程”

          一個(gè)比較官方的定義,“僵尸進(jìn)程”是指完成執(zhí)行(通過(guò)exit系統(tǒng)調(diào)用,或運(yùn)行時(shí)發(fā)生致命錯(cuò)誤或收到終止信號(hào)所致),但在操作系統(tǒng)的進(jìn)程表中仍然存在其進(jìn)程控制塊,處于"終止?fàn)顟B(tài)"的進(jìn)程。

          清理“僵尸進(jìn)程”的思路主要有

          • 將父進(jìn)程中對(duì)SIGCHLD信號(hào)的處理函數(shù)設(shè)為SIG_IGN(忽略信號(hào));
          • fork兩次并殺死一級(jí)子進(jìn)程,令二級(jí)子進(jìn)程成為孤兒進(jìn)程而被init所“收養(yǎng)”、清理

          目前可以實(shí)現(xiàn)的開源方案

          Tini

          tini容器init是一個(gè)最小化的init系統(tǒng),運(yùn)行在容器內(nèi)部,用于啟動(dòng)一個(gè)子進(jìn)程,并等待進(jìn)程退出時(shí)清理僵尸和執(zhí)行信號(hào)轉(zhuǎn)發(fā)

          優(yōu)點(diǎn)

          • tini可以避免應(yīng)用程序生成僵尸進(jìn)程

          • tini可以處理Docker進(jìn)程中運(yùn)行的程序的信號(hào),通過(guò)TiniSIGTERM 可以終止進(jìn)程,不需要你明確安裝一個(gè)信號(hào)處理器

          示例

          #?Add?Tini
          ENV?TINI_VERSION?v0.19.0
          ADD?https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini?/tini
          RUN?chmod?+x?/tini
          ENTRYPOINT?["/tini",?"--"]

          #?Run?your?program?under?Tini
          CMD?["/your/program",?"-and",?"-its",?"arguments"]
          #?or?docker?run?your-image?/your/program?...

          dumb-init

          dumb-init會(huì)向子進(jìn)程的進(jìn)程組發(fā)送其收到的信號(hào)。例如 bash 接收到信號(hào)之后,不會(huì)向子進(jìn)程發(fā)送信號(hào)

          dumb-init也可以通過(guò)設(shè)置環(huán)境變量DUMB_INIT_SETSID=0來(lái)控制只向它的直接子進(jìn)程發(fā)送信號(hào)

          另外dumb-init也會(huì)接管失去父進(jìn)程的進(jìn)程,確保其能正常退出

          示例

          FROM?alpine:3.11.5
          RUN?sed?-i?"s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g"?/etc/apk/repositories?\
          ????&&?apk?add?--no-cache?dumb-init


          #?Runs?"/usr/bin/dumb-init?--?/my/script?--with?--args"
          ENTRYPOINT?["dumb-init",?"--"]

          #?or?if?you?use?--rewrite?or?other?cli?flags
          #?ENTRYPOINT?["dumb-init",?"--rewrite",?"2:3",?"--"]

          CMD?["/my/script",?"--with",?"--args"]

          4.4 降權(quán)啟動(dòng)

          很多情況下,容器中的進(jìn)程需要降權(quán)啟動(dòng)以保證安全性,這就和我們?cè)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(150, 84, 181);">vm上運(yùn)行一個(gè)nginx服務(wù)一樣,最好通過(guò)特定的降權(quán)用戶去運(yùn)行

          舉例,tomcat鏡像

          ...
          USER?tomcat
          WORKDIR?/usr/local/tomcat
          EXPOSE?8080
          ENTRYPOINT?["catalina.sh","run"]

          如果在某些情況下需要使用sudo權(quán)限,在docker官方避免安裝或使用sudosudo因?yàn)樗哂胁豢深A(yù)測(cè)的TTY和可能導(dǎo)致問(wèn)題的信號(hào)轉(zhuǎn)發(fā)行為。如果必須,例如將守護(hù)進(jìn)程初始化為 root但將其作為非運(yùn)行root,推薦使用gosu

          例如,Postgres 官方鏡像[5] 使用以下腳本作為其ENTRYPOINT

          #!/bin/bash
          set?-e

          if?[?"$1"?=?'postgres'?];?then
          ????chown?-R?postgres?"$PGDATA"

          ????if?[?-z?"$(ls?-A?"$PGDATA")"?];?then
          ????????gosu?postgres?initdb
          ????fi

          ????exec?gosu?postgres?"$@"
          fi

          exec?"$@"

          4.5 底層庫(kù)依賴

          很多時(shí)候,服務(wù)依賴一些底層庫(kù)的支持,這里以基于alpine基礎(chǔ)鏡像構(gòu)建java鏡像舉個(gè)栗子

          alpine為了精簡(jiǎn)本身并沒有安裝太多的常用軟件,所以如果要使用jdk/jre的話就需要glibc,而glibc需要先得到ca-certificates證書服務(wù)(安裝glibc前置依賴)才能安裝

          alpine跑了jdk8的鏡像結(jié)果發(fā)現(xiàn)jdk無(wú)法執(zhí)行。究其原因,java是基于GUN Standard C library(glibc)alpine是基于MUSL libc(mini libc),所以alpine需要安裝glibc的庫(kù)

          5、小結(jié)

          本文簡(jiǎn)要分析了Dockerfile為什么這么大的幾個(gè)主要原因,并且根據(jù)生產(chǎn)經(jīng)驗(yàn)羅列了一些優(yōu)化鏡像大小的措施以及其他方面常用的處理辦法,很多技巧性的內(nèi)容,比較雜亂,就不一一提及了 ~

          See you ~

          參考資料

          [1]

          https://www.ssgeek.com/post/git-mu-lu-wei-shi-me-zhe-me-da/

          [2]

          https://docs.docker.com/develop/develop-images/baseimages/

          [3]

          https://docs.docker.com/engine/reference/commandline/dockerd/#description

          [4]

          https://www.ssgeek.com/post/k8s-huan-jing-xia-chu-li-rong-qi-shi-jian-wen-ti-de-duo-chong-zi-shi/

          [5]

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

          歡迎進(jìn)群一起進(jìn)行技術(shù)交流

          加群方式:公眾號(hào)消息私信“加群或加我好友再加群均可

          瀏覽 58
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久综合五月丁香六月 | 亚洲视频在线观看者 | www.黄色视频在线观看 | 一级a黄色 | 人人草人人搞 |