[{"data":1,"prerenderedAt":458},["ShallowReactive",2],{"content-\u002Fcontents\u002Fdockerstudy":3,"surroundPost-\u002Fcontents\u002Fdockerstudy":449},{"id":4,"title":5,"body":6,"createdAt":436,"description":437,"draft":438,"extension":439,"meta":440,"navigation":441,"path":442,"seo":443,"stem":444,"tags":445,"thumbnail":447,"updatedAt":436,"__hash__":448},"contents\u002Fcontents\u002Fdockerstudy.md","初心者から中級者のためのDocker理解",{"type":7,"value":8,"toc":427},"minimark",[9,13,18,29,32,53,61,66,73,76,94,98,101,104,107,117,120,150,153,156,162,165,171,178,184,190,193,197,200,208,211,234,237,241,244,247,250,253,256,263,269,272,275,282,285,288,291,297,300,303,306,312,315,319,423],[10,11,12],"p",{},"Docker をなんとなく使っていたけど、改めて勉強したいと思い自分の気になったことを中心に調べてみました。\n間違い等あるかもしれないのでご注意ください。",[14,15,17],"h2",{"id":16},"docker-を使用するまでの流れ","Docker を使用するまでの流れ",[10,19,20,21,28],{},"ここでは、Dockerfile の記述から実際に使うまでどういう流れになっているのかを俯瞰します。\nDocker のインストール方法は",[22,23,27],"a",{"href":24,"rel":25},"https:\u002F\u002Fdocs.docker.com\u002Fget-docker\u002F",[26],"nofollow","公式サイト","に委ねます。",[10,30,31],{},"まず、Docker は基本的に build→run という手順で使います。",[33,34,35,45],"ol",{},[36,37,38,39],"li",{},"docker build\n",[40,41,42],"ul",{},[36,43,44],{},"Dockerfile と Context からコンテナイメージを作る",[36,46,47,48],{},"docker run\n",[40,49,50],{},[36,51,52],{},"コンテナイメージを実際に実行する",[10,54,55,56,60],{},"その他開発でよく使うのは",[57,58,59],"code",{},"docker push","です。",[10,62,63,64,60],{},"Docker は作成したイメージを Docker Hub に代表されるレジストリに保管することができます。\nその際に使うのが",[57,65,59],{},[10,67,68,69,72],{},"逆にレジストリからイメージを取得するには",[57,70,71],{},"docker pull","で可能です。",[10,74,75],{},"以下 2 つはに関連する言葉をメモしたものです。",[40,77,78,86],{},[36,79,80,81],{},"ビルドコンテキストとは\n",[40,82,83],{},[36,84,85],{},"ビルド時にカレントディレクトリもしくは指定されたフォルダ配下にあるフォルダやファイルがビルドコンテキストとして Docker デーモンに送られます。",[36,87,88,89],{},".dockerignore\n",[40,90,91],{},[36,92,93],{},"ビルドコンテキストに含めたくないファイルやフォルダを指定できます。これによりビルド時間の短縮が期待できます。書き方は.gitignore とほぼ一緒です。",[14,95,97],{"id":96},"docker-のレイヤについて","Docker のレイヤについて",[10,99,100],{},"Docker でいうレイヤとは Dockerfile に記述される命令（簡単にいうと行）のことを指します。\nDocker イメージはレイヤの集まりとも言えます。",[10,102,103],{},"そして肝心なのは、各レイヤは直前のレイヤの変更差分だけを保持します。",[10,105,106],{},"以下は Hello World を出力するだけの Dockerfile です。",[108,109,114],"pre",{"className":110,"code":112,"language":113},[111],"language-text","# 親イメージ（ベース）\nFROM python:3.8.12-slim\n\n# 作業用ディレクトリを指定\nWORKDIR \u002Fusr\u002Fsrc\u002Fapp\n\n# ホスト上のファイルを現在の場所にコピー\nCOPY hello_world.py .\n\n# コンテナ内でコマンドを実行\nCMD [ \"python\", \"hello_world.py\" ]\n","text",[57,115,112],{"__ignoreMap":116},"",[10,118,119],{},"これをビルドしてコンテナイメージを作成します。\n以下のコマンドで build してみます。（Dockerfile があるフォルダで実行した場合）",[108,121,125],{"className":122,"code":123,"language":124,"meta":116,"style":116},"language-bash shiki shiki-themes github-dark","docker build . -t hello\n","bash",[57,126,127],{"__ignoreMap":116},[128,129,132,136,140,143,147],"span",{"class":130,"line":131},"line",1,[128,133,135],{"class":134},"svObZ","docker",[128,137,139],{"class":138},"sU2Wk"," build",[128,141,142],{"class":138}," .",[128,144,146],{"class":145},"sDLfK"," -t",[128,148,149],{"class":138}," hello\n",[10,151,152],{},"ターミナル の出力を見ると各レイヤごとに 処理されているのがみて取れます。",[10,154,155],{},"例えば、以下のレイヤを CMD 行の前に増やしてみます。",[108,157,160],{"className":158,"code":159,"language":113},[111],"COPY hello_world.py .\n",[57,161,159],{"__ignoreMap":116},[10,163,164],{},"再度ビルドコマンドを実行すると以下のような出力が得られます。",[108,166,169],{"className":167,"code":168,"language":113},[111],"Step 1\u002F5 : FROM python:3.8.12-slim\n ---> 0b4039cc52c9\nStep 2\u002F5 : WORKDIR \u002Fusr\u002Fsrc\u002Fapp\n ---> Using cache\n ---> 3941c721c3f5\nStep 3\u002F5 : COPY hello_world.py .\n ---> Using cache\n ---> 757901c00e9f\nStep 4\u002F5 : COPY add_layer.py .\n ---> 5ab5c6c6c477\nStep 5\u002F5 : CMD [ \"python\", \"hello_world.py\" ]\n ---> Running in dbde703d1433\nRemoving intermediate container dbde703d1433\n ---> f3c7f4146400\nSuccessfully built f3c7f4146400\nSuccessfully tagged hello:v2\n",[57,170,168],{"__ignoreMap":116},[10,172,173,174,177],{},"追加行より以前のレイヤではキャッシュが使われており、新しい行がレイヤとして追加されたのがわかります。\n試しに追加行を",[57,175,176],{},"COPY hello_world.py .","より前にすると、以下のようになります。",[108,179,182],{"className":180,"code":181,"language":113},[111],"Step 1\u002F5 : FROM python:3.8.12-slim\n ---> 0b4039cc52c9\nStep 2\u002F5 : WORKDIR \u002Fusr\u002Fsrc\u002Fapp\n ---> Using cache\n ---> 3941c721c3f5\nStep 3\u002F5 : COPY add_layer.py .\n ---> 6a85eb4aef06\nStep 4\u002F5 : COPY hello_world.py .\n ---> 2c4f11da0ed9\nStep 5\u002F5 : CMD [ \"python\", \"hello_world.py\" ]\n ---> Running in c0b1523aa464\nRemoving intermediate container c0b1523aa464\n ---> 42c4156c2564\nSuccessfully built 42c4156c2564\nSuccessfully tagged hello:v3\n",[57,183,181],{"__ignoreMap":116},[10,185,186,187,189],{},"以前とは異なり、",[57,188,176],{},"の部分でキャッシュが使われていません。\nこのように前のレイヤで変更があった場合はそれ以降のレイヤでは仮に処理が同じでもキャッシュが利用されません。",[10,191,192],{},"つまり、開発等でコンテナに取り込むファイルが頻繁に変更される場合は後ろのレイヤに組み込むことがビルド時間の短縮のためには重要です。",[14,194,196],{"id":195},"docker-hub-を使ってみる","Docker Hub を使ってみる",[10,198,199],{},"続いて先ほどのイメージを利用して Docker Hub にイメージを push してみます。",[10,201,202,203,207],{},"Docker Hub の登録などの事前準備は",[22,204,27],{"href":205,"rel":206},"https:\u002F\u002Fdocs.docker.com\u002Fdocker-hub\u002F",[26],"を参考にしてください。",[10,209,210],{},"イメージの push は以下の手順で行います。",[33,212,213,216,228],{},[36,214,215],{},"push したい Docker イメージの作成",[36,217,218,219],{},"必要があればイメージ名を変更\n",[40,220,221],{},[36,222,223,224,227],{},"push するにはイメージ名が",[57,225,226],{},"\u003CDocker Hubのユーザ名>\u002Fイメージ名","とする必要がある",[36,229,230,233],{},[57,231,232],{},"docker push \u003CDocker Hubのユーザ名>\u002Fイメージ名","で push",[10,235,236],{},"上記ではタグをつけてませんが、タグをつけることも可能です。",[14,238,240],{"id":239},"buildkit-とは","Buildkit とは",[10,242,243],{},"Buildkit とは Docker18.09 以降に使えるようになった機能です。",[10,245,246],{},"基本的にはイメージのビルド時間を短縮してくれる機能です。",[10,248,249],{},"具体的にはビルド処理の並列化やビルドコンテキストの差分転送の最適化などが行われています。",[10,251,252],{},"使ってみると劇的にビルドが早くなるので使わないてはないです。",[10,254,255],{},"特にビルドコンテキストの転送が信じられないくらい早くなります。\n学習済みモデルなどの重たいファイルをビルドコンテキストに含めているとビルドに毎回時間がかかってイライラしましたが、 Buildkit の利用でその問題が解消されました。",[10,257,258,259,262],{},"使うにはビルド時のコマンドの前に",[57,260,261],{},"DOCKER_BUILDKIT=1","をつけるだけです。",[108,264,267],{"className":265,"code":266,"language":113},[111],"DOCKER_BUILDKIT=1 docker build -f docker\u002FDockerfile . -t django:0.1\n",[57,268,266],{"__ignoreMap":116},[14,270,271],{"id":271},"マルチステージビルド",[10,273,274],{},"Docker ではレイヤが増えるほど、イメージのサイズが多くなり扱いづらくなります。",[10,276,277,278,281],{},"従来は、Dockerfile の",[57,279,280],{},"RUN","句をなるべく一つにまとめてレイヤを少なくする工夫が行われていました。",[10,283,284],{},"今はコンテナイメージのサイズを抑える方法としてマルチステージビルドがあります。",[10,286,287],{},"こちらは公式サイトでも Docker 開発のベストプラクティスとして紹介されています。",[10,289,290],{},"例として Django を動かす Dockerfile を作ってみました。",[108,292,295],{"className":293,"code":294,"language":113},[111],"FROM python:3.8-slim\n\nENV PYTHONUNBUFFERED 1\nENV PYTHONPATH \u002Fworkspace\u002F\n\nWORKDIR \u002Fworkspace\u002F\n\nRUN pip install poetry\n\nCOPY init_django.sh pyproject.toml poetry.lock \u002Fworkspace\u002F\n\nRUN poetry config virtualenvs.create false \\\n    && poetry install\n\nCOPY backend \u002Fworkspace\u002F\n\nCMD [ \"sh\", \"init_django.sh\"]\n",[57,296,294],{"__ignoreMap":116},[10,298,299],{},"今回使うプロジェクトは手元にあった機械学習系アプリなのでかなりサイズが大きいです。",[10,301,302],{},"マルチステージ前のサイズが 3.18GB です。",[10,304,305],{},"これを以下のようにマルチステージに書き換えてみます。",[108,307,310],{"className":308,"code":309,"language":113},[111],"FROM python:3.8-slim as builder\n\nWORKDIR \u002Fworkspace\u002F\n\nRUN pip install poetry\n\nCOPY pyproject.toml poetry.lock \u002Fworkspace\u002F\n\nRUN poetry config virtualenvs.create false \\\n    && poetry install\n\nFROM python:3.8-slim\n\nENV PYTHONUNBUFFERED 1\nENV PYTHONPATH \u002Fworkspace\u002F\n\nWORKDIR \u002Fworkspace\u002F\n\nCOPY --from=builder \u002Fusr\u002Flocal\u002Flib\u002Fpython3.8\u002Fsite-packages \u002Fusr\u002Flocal\u002Flib\u002Fpython3.8\u002Fsite-packages\n\nCOPY backend \u002Fworkspace\u002F\nCOPY init_django.sh \u002Fworkspace\u002F\n\nCMD [ \"sh\", \"init_django.sh\"]\n",[57,311,309],{"__ignoreMap":116},[10,313,314],{},"ビルドして image サイズを見てみると 2.25GB！！\n1GB ほど小さくなりました！",[14,316,318],{"id":317},"docker-でよく使うコマンド","Docker でよく使うコマンド",[320,321,322,338],"table",{},[323,324,325],"thead",{},[326,327,328,332,335],"tr",{},[329,330,331],"th",{},"操作",[329,333,334],{},"コマンド",[329,336,337],{},"備考",[339,340,341,353,375,395,408],"tbody",{},[326,342,343,347,350],{},[344,345,346],"td",{},"起動中のコンテナ確認",[344,348,349],{},"docker ps",[344,351,352],{},"なし",[326,354,355,358,365],{},[344,356,357],{},"コンテナイメージビルド",[344,359,360,361,364],{},"docker build -t ",[57,362,363],{},"\u003Cイメージ名>",":0.1",[344,366,367,370,371,374],{},[57,368,369],{},"-t","で",[57,372,373],{},"名前:タグ","を指定できる",[326,376,377,380,389],{},[344,378,379],{},"コンテナ実行",[344,381,382,383,386,387],{},"docker run --name ",[57,384,385],{},"コンテナ名"," ",[57,388,363],{},[344,390,391,394],{},[57,392,393],{},"--name","オプションでコンテナに名前をつけられます",[326,396,397,400,406],{},[344,398,399],{},"イメージ削除",[344,401,402,403],{},"docker rmi ",[57,404,405],{},"\u003Cimage id>",[344,407,352],{},[326,409,410,413,416],{},[344,411,412],{},"使ってない Docker のイメージ、コンテナ、ネットワークを削除",[344,414,415],{},"docker system prune",[344,417,418,419,422],{},"ボリュームを削除したい場合は ",[57,420,421],{},"--volumes","フラグをつける",[424,425,426],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":116,"searchDepth":428,"depth":428,"links":429},2,[430,431,432,433,434,435],{"id":16,"depth":428,"text":17},{"id":96,"depth":428,"text":97},{"id":195,"depth":428,"text":196},{"id":239,"depth":428,"text":240},{"id":271,"depth":428,"text":271},{"id":317,"depth":428,"text":318},"2021-09-12","本記事では曖昧にしていたdockerの知識を整理します。また最近よく見かけるBuildkitやマルチステージビルドを実際に使ってみてどんなものか簡単に紹介しています。",false,"md",{},true,"\u002Fcontents\u002Fdockerstudy",{"title":5,"description":437},"contents\u002Fdockerstudy",[446],"Docker","\u002Fimg\u002Ftwitter-card.png","O6AX6BvkQaQQZR5jWGw4qni-DyDXP87itii_4Nn5sO4",[450,454],{"title":451,"path":452,"stem":453,"children":-1},"Direct Corpus Interaction | Paper Summary","\u002Fcontents\u002Fdirect-corpus-interaction-reading","contents\u002Fdirect-corpus-interaction-reading",{"title":455,"path":456,"stem":457,"children":-1},"Dynamic Skill Lifecycle Management","\u002Fcontents\u002Fdynamic-skill-lifecycle-management","contents\u002Fdynamic-skill-lifecycle-management",1785555956014]