コンテナイメージを作成する際に考慮すべき事項


オープンソースの場合、ほとんどのコンテナイメージはすでに存在します.これらのイメージに基づいてアプリケーション・サービスのイメージを作成するだけです.場合によっては、コンテナ画像を最初から作成する必要がある場合があります.また、これらのイメージはクラウド環境でサービスを提供する可能性があります.この文章はその場合どうすればよいかをまとめたものです.私たちのサービスでは、使用するコンテナ画像は自分の製品をコンテナ化しています.コンテナ画像の容量が大きすぎて、更新するたびに時間がかかり、最適化されていないので、直接構築する必要があります.当時知っていた内容を共有したいです.
コンテナイメージをよりよく作成するには、多くの点を考慮する必要がありますが、基本的にはクラウド環境に構築され、コンテナの拡張性と高可用性を確保します.
そのため、コンテナは優雅に閉じ、迅速に配置するためにコンパクトでなければなりません.
*Gracefuldownとは、受信したリクエストを処理して終了することを意味します.

1.容器画像を小さくする


コンテナ画像が小さい場合、画像のインポートに要する時間を短縮でき、新しいコンテナ画像のインポートとリフレッシュに要する時間を短縮できます.また、画像に使用されていないライブラリを削除することで、攻撃ポイントを低減し、安全性を向上させることができます.
以下に画像を小さくする方法を示します.
  • 最小利用可能な下図
  • を選択する.
    不要なファイルを削除する
  • マルチステージ構築方法は、構築中に必要なツール
  • を排除することができる.

    1.下図を使用してコンテナ画像を作成する


    小さなベースマップに変更してコンテナ画像を作成することは、小さなコンテナ画像を作成するのに最も簡単な方法です.ただし、scratchイメージの欠点は、他のLinuxベースイメージとは異なり、内部にファイルが存在しないため、アプリケーションの実行に関連するすべての設定を直接設定する必要があることです.従って、Linuxであるが、サイズの小さいAlpine Linuxや、Alpine Linuxを用いて作成した容器画像を使用することができる.
    ただし、Alpine Linuxを使用するためには、追加設定が必要な場合もあります.これは、テストの新しい環境を構成するときにデータベースを作成したり、データベースの移行のためにsqlイメージを作成したりしたときの経験です.
    テスト用のサービスを構築するたびにinitスクリプトを手動で変換するのは面倒で、Helmを導入してデータベースバージョンを管理するために、最初の構築時に使用するための新しいsql toolイメージを作成してみます.
    sqlバイナリファイルしか持っていないため、実行に必要な環境構築とバイナリファイルをイメージに入れることができます.次はその画像を生成するコードです.
    FROM alpine:3.14.2
    LABEL maintainer @tmax.co.kr
    
    ENV TB_SID tac0
    ENV TB_HOME /tibero
    ENV TB_DB_NAME tibero
    ENV TB_PORT 8629
    ENV LD_LIBRARY_PATH $TB_HOME/lib:$TB_HOME/client/lib
    ENV PATH $TB_HOME/bin:$TB_HOME/client/bin:$PATH
    
    COPY ./tbsql /tibero
    
    ENTRYPOINT [ "tbsql" ]
    CMD [ "--help" ]
    ただし、このようにイメージを作成する場合は、次のエラーを確認できます.
    standard_init_linux.go:228: exec user process caused: no such file or directory
    この問題はalpha Linuxがmusl libcを用いて作成されたためであり,tbsqlにはglibcが必要である.この場合、glibcライブラリをインストールしてこそ、問題を解決できます.

    2.不要なファイルを削除


    必要なファイルまたはツールは、ドッキングイメージを構築する場合にのみ使用できます.これらのファイルまたはツールは、削除することで画像を簡略化できます.
  • kubectl画像バージョン1
  • を作成
    From ubuntu:20.04
    
    # kubectl 다운로드를 위한 curl 다운로드
    RUN apt-get update \
        && apt-get install curl -y \
        && apt-get clean
    
    #kubectl 다운로드 및 설치
    RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
        && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
    
    # curl 삭제 
    RUN apt-get remove curl --auto-remove -y
    
    ENTRYPOINT kubectl 
    CMD ["-h"]
    
  • Kubectl画像バージョン2
  • を作成
    From ubuntu:20.04
    
    # kubectl 다운로드를 위한 curl 다운로드, kubectl 다운로드 및 설치, curl 삭제
    RUN apt-get update \
        && apt-get install curl -y \
        && apt-get clean \
        && curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
        && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl \
        && apt-get remove curl --auto-remove -y
    
    ENTRYPOINT kubectl
    CMD ["-h"]
    最初のドッキングファイルでは、必要なパッケージをインストール、実行、削除の3つのレイヤに分割し、2番目のレイヤでは、1つのレイヤからパッケージをインストール、実行、削除しました.
    これはDockerfileを構築したときの結果です.

    両方のファイルで同じコマンドが実行されましたが、画像のサイズに違いがありました.その理由は、コンテナ画像層の構造にある.

    上の図に示すように、ドッキングステーションイメージはベースイメージとして指定されたコンテナイメージを実行し、Dockerfileに指定されたコマンドを順次実行してレイヤーを作成し、レイヤーを積み重ねて別のイメージを作成します.
    したがって、第1のバージョンのDockerfileについては、最後のコマンドからcurlを削除するが、curlは既に第1のレイヤに格納されているため、最後のレイヤを構築中に削除しても、第1のレイヤのサイズは減少しないので、最終画像のサイズは減少しない.

    3.多段階構築


    マルチフェーズコンストラクションとは、コードのコンストラクションプロセスを実際に使用した画像生成プロセスとは別に、コンテナを実行するために必要な環境のみを備えるように画像を形成する方法である.
  • マルチレベルバージョン
  • # syntax=docker/dockerfile:1
    FROM golang:1.16-alpine AS build
    
    # Install tools required for project
    # Run `docker build --no-cache .` to update dependencies
    RUN apk add --no-cache git
    RUN go get github.com/golang/dep/cmd/dep
    
    # List project dependencies with Gopkg.toml and Gopkg.lock
    # These layers are only re-built when Gopkg files are updated
    COPY Gopkg.lock Gopkg.toml /go/src/project/
    WORKDIR /go/src/project/
    # Install library dependencies
    RUN dep ensure -vendor-only
    
    # Copy the entire project and build it
    # This layer is rebuilt when a file changes in the project directory
    COPY . /go/src/project/
    RUN go build -o /bin/project
    
    # This results in a single layer image
    FROM scratch
    COPY --from=build /bin/project /bin/project
    ENTRYPOINT ["/bin/project"]
    CMD ["--help"]
    ドックの正式なドキュメントのベストプラクティスの表示

    2.コンテナを優雅に死なせる


    クラウド環境では、バージョンアップ時にコンテナ内のイメージが置き換えられます.これにより、画像バージョンが変更されたコンテナが削除され、新しいコンテナ画像で起動されます.クバーネディスは、このプロセスでサービスが中断されないように、無停止の導入ポリシーをサポートします.ただし、デフォルトでは、コンテナは削除時にリクエストを受信せず、受信したリクエストをすべて処理できるようにする必要があります.

    クバーネディスでは、駐車終了時に、プロセス終了信号によってコンテナ内部のプロセスを制御して優雅に死ぬ.
    シード終了の順序から,ライフサイクルhookで定義されたhookが最初に実行される.次にSIGTERMをコンテナの1番PIDに送信し、プロセスを正常に終了させようとします.一定時間経過した後(GracePeriodSecondsのデフォルト値が30で終了)プロセスが終了しない場合は、SIGKILLをコンテナに送信してシードを終了します.

    コンテナで実行されるアプリケーションにプロセス終了信号の処理ロジックがない場合はどうなりますか?


    この場合、SIGKILLを使用してプロセスが終了するまで、コンテナは要求を受信し続けます.
    アプリケーションが個別のコマンドでプロセスを正常に閉じることができる場合は、ライフサイクルのフックのpostStopを使用してコマンドを実行して閉じます.
    spec:
      containers:
    	  - name: pod
    		  lifecycle:
            preStop:
              exec:
                command:
                  - /bin/bash
                  - '-c'
                  - /home/tmax/script/stop.sh
    注意:PostStopのコマンド実行時間が指定した終了GracePeriodSecondsよりも長い場合、正常に終了しません.

    3.Dockerfileを作成してアプリケーションをよりよく閉じる


    コンテナで実行されるアプリケーションのライフサイクルはコンテナのライフサイクルと同じであるため、1つのコンテナでアプリケーションを実行する必要があります.複数のアプリケーションを実行している場合、クバーネディスでは、多くのアプリケーションの一部に異常が発生している場合、正常かどうかを判断するのは難しい.これは、クベネディスがコンテナを自動的に再起動できないため、問題を引き起こす可能性があります.
    コンテナ内でアプリケーションを実行する方法は、DockerfileのENTRYPOINTおよびCMDによって決定されます.
  • ENTRYPOINT用法

  • 実行可能ファイルのexecフォーマットの実行
    ENTRYPOINT ["executable", "param1", "param2"]

  • shellコマンドを使用するshell形式
    ENTRYPOINT command param1 param2
  • 上記のアプリケーションのライフサイクルをコンテナのライフサイクルと同じにするには、コンテナが終了すると、プロセス終了信号をアプリケーションのプロセスによく伝達する必要があります.
    プロセス終了信号をアプリケーションに渡すためには、ENTRYPOINTでアプリケーションを1番PIDとして実行し、アプリケーションがプロセス終了信号を処理できるようにしなければならない.
    プロセス終了信号を処理するアプリケーションを直ちに実行すると問題は発生しませんが、アプリケーションを実行するために追加の設定を行うためにshellを実行してからアプリケーションを実行する必要がある場合があります.ただし、shellが次のshellコードを使用してアプリケーションを実行すると、プロセス終了ロジックに問題が発生します.
    From ubunut:20.04
    
    COPY run.sh 
    
    ENTRYPOINT [ "run.sh" ]
    #!/bin/bash
    # run.sh
    
    wsboot -c $WEBTOB_CONFIG_FILE -V
    Shellの場合、終了信号がサブフローに伝達されないため、この場合、アプリケーションは正常に終了できません.この問題を解決するには、execコマンドを使用してアプリケーションを実行し、アプリケーションプロセスをPID 1にする必要があります.
    #!/bin/bash
    
    exec wsboot -c $WEBTOB_CONFIG_FILE -V
    アプリケーションでプロセス終了信号を処理する論理がないためにcustom initも使用できます.
    それ以外にも,画像を構築する際に発生するキャッシュを用いて迅速に構築するためには,層の順序や構造を把握することも重要である.