[{"data":1,"prerenderedAt":1678},["ShallowReactive",2],{"blog-ja-gitlab-ci-container-deployment":3,"blog-ja-gitlab-ci-container-deployment-alt":416},{"id":4,"title":5,"author":6,"body":7,"date":1662,"description":1663,"extension":1664,"image":75,"locale":1665,"meta":1666,"navigation":416,"path":1667,"seo":1668,"stem":1669,"tags":1670,"__hash__":1677},"blog\u002Fblog\u002Fja\u002Fgitlab-ci-container-deployment.md","GitLab ci-cd でコンテナデプロイを自動化する方法","Kubo Team",{"type":8,"value":9,"toc":1637},"minimark",[10,22,27,36,41,49,53,69,178,190,245,248,252,263,342,350,354,361,364,880,884,904,908,919,923,1027,1031,1038,1066,1072,1075,1078,1081,1144,1148,1320,1323,1326,1329,1407,1411,1582,1594,1598,1610,1614,1617,1633],[11,12,13,14,21],"p",{},"GitLab ci-cd は、月間 4 億分以上のパイプライン実行を処理し、3,000 万人以上の開発者に利用されている統合 DevOps プラットフォームです。ソースコード管理、ci-cd、コンテナレジストリ、セキュリティスキャンが一体化されており、Kubernetes へのコンテナデプロイを効率的に自動化できます。",[15,16,20],"a",{"href":17,"rel":18},"https:\u002F\u002Fkubo.hexabase.io\u002F",[19],"nofollow","Kubo"," は GitLab ci-cd との連携にも対応しており、エンタープライズグレードのデプロイパイプラインを構築できます。本記事では、GitLab ci-cd によるコンテナデプロイの実践的な手順を解説します。",[23,24,26],"h2",{"id":25},"gitlab-kubernetes-agent-によるセキュアなクラスタ接続","GitLab Kubernetes Agent によるセキュアなクラスタ接続",[11,28,29,30,35],{},"従来の Kubernetes 連携では、クラスタの API サーバーをインターネットに公開する必要がありましたが、",[15,31,34],{"href":32,"rel":33},"https:\u002F\u002Fdocs.gitlab.com\u002Fuser\u002Fclusters\u002Fagent\u002Fci_cd_workflow\u002F",[19],"GitLab Kubernetes Agent"," はクラスタ内部からの接続を確立することで、セキュリティを大幅に向上させています。",[37,38,40],"h3",{"id":39},"agent-のアーキテクチャ","Agent のアーキテクチャ",[11,42,43,44,48],{},"GitLab Agent は ",[45,46,47],"strong",{},"Pull ベースのアーキテクチャ"," を採用しています。Agent がクラスタ内で動作し、GitLab サーバーに対してアウトバウンド接続を確立します。これにより、Kubernetes API サーバーを外部に公開する必要がありません。",[37,50,52],{"id":51},"agent-の設定手順","Agent の設定手順",[54,55,56,63],"ol",{},[57,58,59,62],"li",{},[45,60,61],{},"Agent の登録",": GitLab プロジェクトで Agent を登録し、トークンを取得",[57,64,65,68],{},[45,66,67],{},"Helm でのインストール",":",[70,71,76],"pre",{"className":72,"code":73,"language":74,"meta":75,"style":75},"language-bash shiki shiki-themes tokyo-night","helm repo add gitlab https:\u002F\u002Fcharts.gitlab.io\nhelm repo update\nhelm upgrade --install gitlab-agent gitlab\u002Fgitlab-agent \\\n  --namespace gitlab-agent --create-namespace \\\n  --set config.token=\u003Cagent-token> \\\n  --set config.kasAddress=wss:\u002F\u002Fkas.gitlab.com\n","bash","",[77,78,79,101,111,133,146,170],"code",{"__ignoreMap":75},[80,81,84,88,92,95,98],"span",{"class":82,"line":83},"line",1,[80,85,87],{"class":86},"sE3pS","helm",[80,89,91],{"class":90},"sPY7s"," repo",[80,93,94],{"class":90}," add",[80,96,97],{"class":90}," gitlab",[80,99,100],{"class":90}," https:\u002F\u002Fcharts.gitlab.io\n",[80,102,104,106,108],{"class":82,"line":103},2,[80,105,87],{"class":86},[80,107,91],{"class":90},[80,109,110],{"class":90}," update\n",[80,112,114,116,119,123,126,129],{"class":82,"line":113},3,[80,115,87],{"class":86},[80,117,118],{"class":90}," upgrade",[80,120,122],{"class":121},"sT800"," --install",[80,124,125],{"class":90}," gitlab-agent",[80,127,128],{"class":90}," gitlab\u002Fgitlab-agent",[80,130,132],{"class":131},"sAklC"," \\\n",[80,134,136,139,141,144],{"class":82,"line":135},4,[80,137,138],{"class":121},"  --namespace",[80,140,125],{"class":90},[80,142,143],{"class":121}," --create-namespace",[80,145,132],{"class":131},[80,147,149,152,155,158,161,165,168],{"class":82,"line":148},5,[80,150,151],{"class":121},"  --set",[80,153,154],{"class":90}," config.token=",[80,156,157],{"class":131},"\u003C",[80,159,160],{"class":90},"agent-toke",[80,162,164],{"class":163},"sGX4V","n",[80,166,167],{"class":131},">",[80,169,132],{"class":131},[80,171,173,175],{"class":82,"line":172},6,[80,174,151],{"class":121},[80,176,177],{"class":90}," config.kasAddress=wss:\u002F\u002Fkas.gitlab.com\n",[54,179,180],{"start":113},[57,181,182,185,186,189],{},[45,183,184],{},"Agent 設定ファイル"," (",[77,187,188],{},".gitlab\u002Fagents\u002F\u003Cagent-name>\u002Fconfig.yaml","):",[70,191,195],{"className":192,"code":193,"language":194,"meta":75,"style":75},"language-yaml shiki shiki-themes tokyo-night","ci_access:\n  projects:\n    - id: your-group-your-project\n  groups:\n    - id: your-group\n","yaml",[77,196,197,206,213,227,234],{"__ignoreMap":75},[80,198,199,203],{"class":82,"line":83},[80,200,202],{"class":201},"s0U2E","ci_access",[80,204,205],{"class":131},":\n",[80,207,208,211],{"class":82,"line":103},[80,209,210],{"class":201},"  projects",[80,212,205],{"class":131},[80,214,215,219,222,224],{"class":82,"line":113},[80,216,218],{"class":217},"sgJMe","    -",[80,220,221],{"class":201}," id",[80,223,68],{"class":131},[80,225,226],{"class":90}," your-group-your-project\n",[80,228,229,232],{"class":82,"line":135},[80,230,231],{"class":201},"  groups",[80,233,205],{"class":131},[80,235,236,238,240,242],{"class":82,"line":148},[80,237,218],{"class":217},[80,239,221],{"class":201},[80,241,68],{"class":131},[80,243,244],{"class":90}," your-group\n",[11,246,247],{},"最大 500 のプロジェクトまたはグループを 1 つの Agent に紐づけられます。",[37,249,251],{"id":250},"impersonation-によるアクセス制御","Impersonation によるアクセス制御",[11,253,254,258,259,262],{},[15,255,257],{"href":32,"rel":256},[19],"GitLab の公式ドキュメント","によれば、デフォルトでは ci-cd ジョブは Agent インストール時の ServiceAccount の全権限を継承します。本番環境では必ず ",[45,260,261],{},"Impersonation"," を設定し、ジョブごとに最小権限を適用してください。",[70,264,266],{"className":192,"code":265,"language":194,"meta":75,"style":75},"ci_access:\n  projects:\n    - id: your-group-your-project\n      default_namespace: production\n      access_as:\n        impersonate:\n          username: gitlab-ci-deploy\n          groups:\n            - deployers\n",[77,267,268,274,280,290,300,307,314,325,333],{"__ignoreMap":75},[80,269,270,272],{"class":82,"line":83},[80,271,202],{"class":201},[80,273,205],{"class":131},[80,275,276,278],{"class":82,"line":103},[80,277,210],{"class":201},[80,279,205],{"class":131},[80,281,282,284,286,288],{"class":82,"line":113},[80,283,218],{"class":217},[80,285,221],{"class":201},[80,287,68],{"class":131},[80,289,226],{"class":90},[80,291,292,295,297],{"class":82,"line":135},[80,293,294],{"class":201},"      default_namespace",[80,296,68],{"class":131},[80,298,299],{"class":90}," production\n",[80,301,302,305],{"class":82,"line":148},[80,303,304],{"class":201},"      access_as",[80,306,205],{"class":131},[80,308,309,312],{"class":82,"line":172},[80,310,311],{"class":201},"        impersonate",[80,313,205],{"class":131},[80,315,317,320,322],{"class":82,"line":316},7,[80,318,319],{"class":201},"          username",[80,321,68],{"class":131},[80,323,324],{"class":90}," gitlab-ci-deploy\n",[80,326,328,331],{"class":82,"line":327},8,[80,329,330],{"class":201},"          groups",[80,332,205],{"class":131},[80,334,336,339],{"class":82,"line":335},9,[80,337,338],{"class":217},"            -",[80,340,341],{"class":90}," deployers\n",[11,343,344,349],{},[15,345,348],{"href":346,"rel":347},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fcaptain-ai\u002F",[19],"Captain.AI"," では、このような複雑なアクセス制御設定も AI が支援します。",[23,351,353],{"id":352},"gitlab-ciyml-によるパイプライン構築",".gitlab-ci.yml によるパイプライン構築",[11,355,356,357,360],{},"GitLab ci-cd のパイプラインは ",[77,358,359],{},".gitlab-ci.yml"," で定義します。コンテナデプロイの典型的なパイプライン構成を見ていきましょう。",[37,362,363],{"id":363},"基本パイプライン構成",[70,365,367],{"className":192,"code":366,"language":194,"meta":75,"style":75},"stages:\n  - build\n  - test\n  - scan\n  - deploy-staging\n  - deploy-production\n\nvariables:\n  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\n  KUBE_CONTEXT: your-group\u002Fyour-project:production-agent\n\nbuild:\n  stage: build\n  image: docker:27\n  services:\n    - docker:27-dind\n  script:\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker build -t $IMAGE_TAG .\n    - docker push $IMAGE_TAG\n\ntest:\n  stage: test\n  image: $IMAGE_TAG\n  script:\n    - npm ci\n    - npm test\n\ncontainer-scan:\n  stage: scan\n  image:\n    name: aquasec\u002Ftrivy:latest\n    entrypoint: [\"\"]\n  script:\n    - trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_TAG\n\ndeploy-staging:\n  stage: deploy-staging\n  image:\n    name: bitnami\u002Fkubectl:latest\n    entrypoint: [\"\"]\n  script:\n    - kubectl config use-context $KUBE_CONTEXT\n    - kubectl set image deployment-my-app app=$image_tag -n staging\n    - kubectl rollout status deployment-my-app -n staging\n  environment:\n    name: staging\n\ndeploy-production:\n  stage: deploy-production\n  image:\n    name: bitnami\u002Fkubectl:latest\n    entrypoint: [\"\"]\n  script:\n    - kubectl config use-context $KUBE_CONTEXT\n    - kubectl set image deployment-my-app app=$image_tag -n production\n    - kubectl rollout status deployment-my-app -n production\n  environment:\n    name: production\n  when: manual\n  only:\n    - main\n",[77,368,369,376,384,391,398,405,412,418,425,435,446,451,459,469,480,488,496,504,512,520,528,533,541,550,560,567,575,583,588,596,605,612,623,640,647,655,660,668,677,684,694,707,714,722,730,738,746,756,761,769,778,785,794,807,814,821,829,837,844,853,864,872],{"__ignoreMap":75},[80,370,371,374],{"class":82,"line":83},[80,372,373],{"class":201},"stages",[80,375,205],{"class":131},[80,377,378,381],{"class":82,"line":103},[80,379,380],{"class":217},"  -",[80,382,383],{"class":90}," build\n",[80,385,386,388],{"class":82,"line":113},[80,387,380],{"class":217},[80,389,390],{"class":90}," test\n",[80,392,393,395],{"class":82,"line":135},[80,394,380],{"class":217},[80,396,397],{"class":90}," scan\n",[80,399,400,402],{"class":82,"line":148},[80,401,380],{"class":217},[80,403,404],{"class":90}," deploy-staging\n",[80,406,407,409],{"class":82,"line":172},[80,408,380],{"class":217},[80,410,411],{"class":90}," deploy-production\n",[80,413,414],{"class":82,"line":316},[80,415,417],{"emptyLinePlaceholder":416},true,"\n",[80,419,420,423],{"class":82,"line":327},[80,421,422],{"class":201},"variables",[80,424,205],{"class":131},[80,426,427,430,432],{"class":82,"line":335},[80,428,429],{"class":201},"  IMAGE_TAG",[80,431,68],{"class":131},[80,433,434],{"class":90}," $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\n",[80,436,438,441,443],{"class":82,"line":437},10,[80,439,440],{"class":201},"  KUBE_CONTEXT",[80,442,68],{"class":131},[80,444,445],{"class":90}," your-group\u002Fyour-project:production-agent\n",[80,447,449],{"class":82,"line":448},11,[80,450,417],{"emptyLinePlaceholder":416},[80,452,454,457],{"class":82,"line":453},12,[80,455,456],{"class":201},"build",[80,458,205],{"class":131},[80,460,462,465,467],{"class":82,"line":461},13,[80,463,464],{"class":201},"  stage",[80,466,68],{"class":131},[80,468,383],{"class":90},[80,470,472,475,477],{"class":82,"line":471},14,[80,473,474],{"class":201},"  image",[80,476,68],{"class":131},[80,478,479],{"class":90}," docker:27\n",[80,481,483,486],{"class":82,"line":482},15,[80,484,485],{"class":201},"  services",[80,487,205],{"class":131},[80,489,491,493],{"class":82,"line":490},16,[80,492,218],{"class":217},[80,494,495],{"class":90}," docker:27-dind\n",[80,497,499,502],{"class":82,"line":498},17,[80,500,501],{"class":201},"  script",[80,503,205],{"class":131},[80,505,507,509],{"class":82,"line":506},18,[80,508,218],{"class":217},[80,510,511],{"class":90}," docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n",[80,513,515,517],{"class":82,"line":514},19,[80,516,218],{"class":217},[80,518,519],{"class":90}," docker build -t $IMAGE_TAG .\n",[80,521,523,525],{"class":82,"line":522},20,[80,524,218],{"class":217},[80,526,527],{"class":90}," docker push $IMAGE_TAG\n",[80,529,531],{"class":82,"line":530},21,[80,532,417],{"emptyLinePlaceholder":416},[80,534,536,539],{"class":82,"line":535},22,[80,537,538],{"class":201},"test",[80,540,205],{"class":131},[80,542,544,546,548],{"class":82,"line":543},23,[80,545,464],{"class":201},[80,547,68],{"class":131},[80,549,390],{"class":90},[80,551,553,555,557],{"class":82,"line":552},24,[80,554,474],{"class":201},[80,556,68],{"class":131},[80,558,559],{"class":90}," $IMAGE_TAG\n",[80,561,563,565],{"class":82,"line":562},25,[80,564,501],{"class":201},[80,566,205],{"class":131},[80,568,570,572],{"class":82,"line":569},26,[80,571,218],{"class":217},[80,573,574],{"class":90}," npm ci\n",[80,576,578,580],{"class":82,"line":577},27,[80,579,218],{"class":217},[80,581,582],{"class":90}," npm test\n",[80,584,586],{"class":82,"line":585},28,[80,587,417],{"emptyLinePlaceholder":416},[80,589,591,594],{"class":82,"line":590},29,[80,592,593],{"class":201},"container-scan",[80,595,205],{"class":131},[80,597,599,601,603],{"class":82,"line":598},30,[80,600,464],{"class":201},[80,602,68],{"class":131},[80,604,397],{"class":90},[80,606,608,610],{"class":82,"line":607},31,[80,609,474],{"class":201},[80,611,205],{"class":131},[80,613,615,618,620],{"class":82,"line":614},32,[80,616,617],{"class":201},"    name",[80,619,68],{"class":131},[80,621,622],{"class":90}," aquasec\u002Ftrivy:latest\n",[80,624,626,629,631,634,637],{"class":82,"line":625},33,[80,627,628],{"class":201},"    entrypoint",[80,630,68],{"class":131},[80,632,633],{"class":131}," [",[80,635,636],{"class":131},"\"\"",[80,638,639],{"class":131},"]\n",[80,641,643,645],{"class":82,"line":642},34,[80,644,501],{"class":201},[80,646,205],{"class":131},[80,648,650,652],{"class":82,"line":649},35,[80,651,218],{"class":217},[80,653,654],{"class":90}," trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_TAG\n",[80,656,658],{"class":82,"line":657},36,[80,659,417],{"emptyLinePlaceholder":416},[80,661,663,666],{"class":82,"line":662},37,[80,664,665],{"class":201},"deploy-staging",[80,667,205],{"class":131},[80,669,671,673,675],{"class":82,"line":670},38,[80,672,464],{"class":201},[80,674,68],{"class":131},[80,676,404],{"class":90},[80,678,680,682],{"class":82,"line":679},39,[80,681,474],{"class":201},[80,683,205],{"class":131},[80,685,687,689,691],{"class":82,"line":686},40,[80,688,617],{"class":201},[80,690,68],{"class":131},[80,692,693],{"class":90}," bitnami\u002Fkubectl:latest\n",[80,695,697,699,701,703,705],{"class":82,"line":696},41,[80,698,628],{"class":201},[80,700,68],{"class":131},[80,702,633],{"class":131},[80,704,636],{"class":131},[80,706,639],{"class":131},[80,708,710,712],{"class":82,"line":709},42,[80,711,501],{"class":201},[80,713,205],{"class":131},[80,715,717,719],{"class":82,"line":716},43,[80,718,218],{"class":217},[80,720,721],{"class":90}," kubectl config use-context $KUBE_CONTEXT\n",[80,723,725,727],{"class":82,"line":724},44,[80,726,218],{"class":217},[80,728,729],{"class":90}," kubectl set image deployment-my-app app=$image_tag -n staging\n",[80,731,733,735],{"class":82,"line":732},45,[80,734,218],{"class":217},[80,736,737],{"class":90}," kubectl rollout status deployment-my-app -n staging\n",[80,739,741,744],{"class":82,"line":740},46,[80,742,743],{"class":201},"  environment",[80,745,205],{"class":131},[80,747,749,751,753],{"class":82,"line":748},47,[80,750,617],{"class":201},[80,752,68],{"class":131},[80,754,755],{"class":90}," staging\n",[80,757,759],{"class":82,"line":758},48,[80,760,417],{"emptyLinePlaceholder":416},[80,762,764,767],{"class":82,"line":763},49,[80,765,766],{"class":201},"deploy-production",[80,768,205],{"class":131},[80,770,772,774,776],{"class":82,"line":771},50,[80,773,464],{"class":201},[80,775,68],{"class":131},[80,777,411],{"class":90},[80,779,781,783],{"class":82,"line":780},51,[80,782,474],{"class":201},[80,784,205],{"class":131},[80,786,788,790,792],{"class":82,"line":787},52,[80,789,617],{"class":201},[80,791,68],{"class":131},[80,793,693],{"class":90},[80,795,797,799,801,803,805],{"class":82,"line":796},53,[80,798,628],{"class":201},[80,800,68],{"class":131},[80,802,633],{"class":131},[80,804,636],{"class":131},[80,806,639],{"class":131},[80,808,810,812],{"class":82,"line":809},54,[80,811,501],{"class":201},[80,813,205],{"class":131},[80,815,817,819],{"class":82,"line":816},55,[80,818,218],{"class":217},[80,820,721],{"class":90},[80,822,824,826],{"class":82,"line":823},56,[80,825,218],{"class":217},[80,827,828],{"class":90}," kubectl set image deployment-my-app app=$image_tag -n production\n",[80,830,832,834],{"class":82,"line":831},57,[80,833,218],{"class":217},[80,835,836],{"class":90}," kubectl rollout status deployment-my-app -n production\n",[80,838,840,842],{"class":82,"line":839},58,[80,841,743],{"class":201},[80,843,205],{"class":131},[80,845,847,849,851],{"class":82,"line":846},59,[80,848,617],{"class":201},[80,850,68],{"class":131},[80,852,299],{"class":90},[80,854,856,859,861],{"class":82,"line":855},60,[80,857,858],{"class":201},"  when",[80,860,68],{"class":131},[80,862,863],{"class":90}," manual\n",[80,865,867,870],{"class":82,"line":866},61,[80,868,869],{"class":201},"  only",[80,871,205],{"class":131},[80,873,875,877],{"class":82,"line":874},62,[80,876,218],{"class":217},[80,878,879],{"class":90}," main\n",[37,881,883],{"id":882},"gitlab-container-registry-の活用","GitLab Container Registry の活用",[11,885,886,887,892,893,896,897,896,900,903],{},"GitLab には",[15,888,891],{"href":889,"rel":890},"https:\u002F\u002Fdocs.gitlab.com\u002Fuser\u002Fpackages\u002Fcontainer_registry\u002F",[19],"組み込みのコンテナレジストリ","が含まれており、追加のレジストリサービスを構築する必要がありません。",[77,894,895],{},"$CI_REGISTRY","、",[77,898,899],{},"$CI_REGISTRY_USER",[77,901,902],{},"$CI_REGISTRY_PASSWORD"," といった定義済み変数で、シームレスに認証できます。",[23,905,907],{"id":906},"auto-devops-による自動パイプライン","Auto DevOps による自動パイプライン",[11,909,910,915,916,918],{},[15,911,914],{"href":912,"rel":913},"https:\u002F\u002Fdocs.gitlab.com\u002Ftopics\u002Fautodevops\u002F",[19],"GitLab Auto DevOps"," は、",[77,917,359],{}," を一切書かなくても、アプリケーションの言語とフレームワークを自動検出してパイプラインを構築する機能です。",[37,920,922],{"id":921},"auto-devops-のステージ","Auto DevOps のステージ",[924,925,926,942],"table",{},[927,928,929],"thead",{},[930,931,932,936,939],"tr",{},[933,934,935],"th",{},"ステージ",[933,937,938],{},"機能",[933,940,941],{},"ツール",[943,944,945,957,968,979,990,1005,1016],"tbody",{},[930,946,947,951,954],{},[948,949,950],"td",{},"Auto Build",[948,952,953],{},"Dockerfile またはビルドパック検出",[948,955,956],{},"Cloud Native Buildpacks",[930,958,959,962,965],{},[948,960,961],{},"Auto Test",[948,963,964],{},"言語固有のテスト実行",[948,966,967],{},"言語固有ツール",[930,969,970,973,976],{},[948,971,972],{},"Auto Code Quality",[948,974,975],{},"コード品質分析",[948,977,978],{},"Code Climate",[930,980,981,984,987],{},[948,982,983],{},"Auto SAST",[948,985,986],{},"静的セキュリティテスト",[948,988,989],{},"GitLab SAST",[930,991,992,995,998],{},[948,993,994],{},"Auto Container Scanning",[948,996,997],{},"コンテナ脆弱性スキャン",[948,999,1000],{},[15,1001,1004],{"href":1002,"rel":1003},"https:\u002F\u002Ftrivy.dev\u002F",[19],"Trivy",[930,1006,1007,1010,1013],{},[948,1008,1009],{},"Auto Deploy",[948,1011,1012],{},"Kubernetes デプロイ",[948,1014,1015],{},"Helm",[930,1017,1018,1021,1024],{},[948,1019,1020],{},"Auto Monitoring",[948,1022,1023],{},"実行時監視",[948,1025,1026],{},"Prometheus",[37,1028,1030],{"id":1029},"kubernetes-agent-との連携","Kubernetes Agent との連携",[11,1032,1033,1034,1037],{},"Auto DevOps で Kubernetes Agent を使用する場合、",[77,1035,1036],{},"KUBE_CONTEXT"," 変数でエージェントのコンテキストを指定します。",[70,1039,1041],{"className":192,"code":1040,"language":194,"meta":75,"style":75},"# ci-cd Variables で設定\nKUBE_CONTEXT: your-group\u002Fyour-project:staging-agent  # ステージング用\n# production 環境では別の Agent を指定可能\n",[77,1042,1043,1049,1061],{"__ignoreMap":75},[80,1044,1045],{"class":82,"line":83},[80,1046,1048],{"class":1047},"sbD-w","# ci-cd Variables で設定\n",[80,1050,1051,1053,1055,1058],{"class":82,"line":103},[80,1052,1036],{"class":201},[80,1054,68],{"class":131},[80,1056,1057],{"class":90}," your-group\u002Fyour-project:staging-agent",[80,1059,1060],{"class":1047},"  # ステージング用\n",[80,1062,1063],{"class":82,"line":113},[80,1064,1065],{"class":1047},"# production 環境では別の Agent を指定可能\n",[11,1067,1068,1071],{},[15,1069,20],{"href":17,"rel":1070},[19]," のマネージド環境では、Auto DevOps の設定が事前最適化されており、プロジェクト作成後すぐに自動パイプラインを開始できます。",[23,1073,1074],{"id":1074},"マルチ環境デプロイ戦略",[11,1076,1077],{},"実践的なデプロイでは、環境ごとに異なる設定と承認フローが必要です。",[37,1079,1080],{"id":1080},"環境スコープ変数",[70,1082,1084],{"className":192,"code":1083,"language":194,"meta":75,"style":75},"# GitLab ci-cd Variables（UI で設定）\n# Environment: staging\nREPLICAS: 1\nDB_HOST: staging-db.internal\n\n# Environment: production\nREPLICAS: 3\nDB_HOST: production-db.internal\n",[77,1085,1086,1091,1096,1107,1117,1121,1126,1135],{"__ignoreMap":75},[80,1087,1088],{"class":82,"line":83},[80,1089,1090],{"class":1047},"# GitLab ci-cd Variables（UI で設定）\n",[80,1092,1093],{"class":82,"line":103},[80,1094,1095],{"class":1047},"# Environment: staging\n",[80,1097,1098,1101,1103],{"class":82,"line":113},[80,1099,1100],{"class":201},"REPLICAS",[80,1102,68],{"class":131},[80,1104,1106],{"class":1105},"sOJ5S"," 1\n",[80,1108,1109,1112,1114],{"class":82,"line":135},[80,1110,1111],{"class":201},"DB_HOST",[80,1113,68],{"class":131},[80,1115,1116],{"class":90}," staging-db.internal\n",[80,1118,1119],{"class":82,"line":148},[80,1120,417],{"emptyLinePlaceholder":416},[80,1122,1123],{"class":82,"line":172},[80,1124,1125],{"class":1047},"# Environment: production\n",[80,1127,1128,1130,1132],{"class":82,"line":316},[80,1129,1100],{"class":201},[80,1131,68],{"class":131},[80,1133,1134],{"class":1105}," 3\n",[80,1136,1137,1139,1141],{"class":82,"line":327},[80,1138,1111],{"class":201},[80,1140,68],{"class":131},[80,1142,1143],{"class":90}," production-db.internal\n",[37,1145,1147],{"id":1146},"review-apps-による動的環境","Review Apps による動的環境",[70,1149,1151],{"className":192,"code":1150,"language":194,"meta":75,"style":75},"review:\n  stage: deploy-staging\n  script:\n    - kubectl config use-context $KUBE_CONTEXT\n    - helm upgrade --install review-$ci_commit_ref_slug .-chart \\\n        --namespace review \\\n        --set image.tag=$CI_COMMIT_SHA \\\n        --set ingress.host=$CI_COMMIT_REF_SLUG.review.example.com\n  environment:\n    name: review\u002F$CI_COMMIT_REF_SLUG\n    url: https:\u002F\u002F$CI_COMMIT_REF_SLUG.review.example.com\n    on_stop: stop-review\n  only:\n    - merge_requests\n\nstop-review:\n  stage: deploy-staging\n  script:\n    - kubectl config use-context $KUBE_CONTEXT\n    - helm uninstall review-$CI_COMMIT_REF_SLUG --namespace review\n  environment:\n    name: review\u002F$CI_COMMIT_REF_SLUG\n    action: stop\n  when: manual\n",[77,1152,1153,1160,1168,1174,1180,1187,1192,1197,1202,1208,1217,1227,1237,1243,1250,1254,1261,1269,1275,1281,1288,1294,1302,1312],{"__ignoreMap":75},[80,1154,1155,1158],{"class":82,"line":83},[80,1156,1157],{"class":201},"review",[80,1159,205],{"class":131},[80,1161,1162,1164,1166],{"class":82,"line":103},[80,1163,464],{"class":201},[80,1165,68],{"class":131},[80,1167,404],{"class":90},[80,1169,1170,1172],{"class":82,"line":113},[80,1171,501],{"class":201},[80,1173,205],{"class":131},[80,1175,1176,1178],{"class":82,"line":135},[80,1177,218],{"class":217},[80,1179,721],{"class":90},[80,1181,1182,1184],{"class":82,"line":148},[80,1183,218],{"class":217},[80,1185,1186],{"class":90}," helm upgrade --install review-$ci_commit_ref_slug .-chart \\\n",[80,1188,1189],{"class":82,"line":172},[80,1190,1191],{"class":90},"        --namespace review \\\n",[80,1193,1194],{"class":82,"line":316},[80,1195,1196],{"class":90},"        --set image.tag=$CI_COMMIT_SHA \\\n",[80,1198,1199],{"class":82,"line":327},[80,1200,1201],{"class":90},"        --set ingress.host=$CI_COMMIT_REF_SLUG.review.example.com\n",[80,1203,1204,1206],{"class":82,"line":335},[80,1205,743],{"class":201},[80,1207,205],{"class":131},[80,1209,1210,1212,1214],{"class":82,"line":437},[80,1211,617],{"class":201},[80,1213,68],{"class":131},[80,1215,1216],{"class":90}," review\u002F$CI_COMMIT_REF_SLUG\n",[80,1218,1219,1222,1224],{"class":82,"line":448},[80,1220,1221],{"class":201},"    url",[80,1223,68],{"class":131},[80,1225,1226],{"class":90}," https:\u002F\u002F$CI_COMMIT_REF_SLUG.review.example.com\n",[80,1228,1229,1232,1234],{"class":82,"line":453},[80,1230,1231],{"class":201},"    on_stop",[80,1233,68],{"class":131},[80,1235,1236],{"class":90}," stop-review\n",[80,1238,1239,1241],{"class":82,"line":461},[80,1240,869],{"class":201},[80,1242,205],{"class":131},[80,1244,1245,1247],{"class":82,"line":471},[80,1246,218],{"class":217},[80,1248,1249],{"class":90}," merge_requests\n",[80,1251,1252],{"class":82,"line":482},[80,1253,417],{"emptyLinePlaceholder":416},[80,1255,1256,1259],{"class":82,"line":490},[80,1257,1258],{"class":201},"stop-review",[80,1260,205],{"class":131},[80,1262,1263,1265,1267],{"class":82,"line":498},[80,1264,464],{"class":201},[80,1266,68],{"class":131},[80,1268,404],{"class":90},[80,1270,1271,1273],{"class":82,"line":506},[80,1272,501],{"class":201},[80,1274,205],{"class":131},[80,1276,1277,1279],{"class":82,"line":514},[80,1278,218],{"class":217},[80,1280,721],{"class":90},[80,1282,1283,1285],{"class":82,"line":522},[80,1284,218],{"class":217},[80,1286,1287],{"class":90}," helm uninstall review-$CI_COMMIT_REF_SLUG --namespace review\n",[80,1289,1290,1292],{"class":82,"line":530},[80,1291,743],{"class":201},[80,1293,205],{"class":131},[80,1295,1296,1298,1300],{"class":82,"line":535},[80,1297,617],{"class":201},[80,1299,68],{"class":131},[80,1301,1216],{"class":90},[80,1303,1304,1307,1309],{"class":82,"line":543},[80,1305,1306],{"class":201},"    action",[80,1308,68],{"class":131},[80,1310,1311],{"class":90}," stop\n",[80,1313,1314,1316,1318],{"class":82,"line":552},[80,1315,858],{"class":201},[80,1317,68],{"class":131},[80,1319,863],{"class":90},[11,1321,1322],{},"マージリクエストごとに動的な Review 環境が作成され、レビュアーが実際のアプリケーションを確認できます。マージ後に自動または手動でクリーンアップされます。",[23,1324,1325],{"id":1325},"パイプラインの高速化とコスト最適化",[37,1327,1328],{"id":1328},"キャッシュ戦略",[70,1330,1332],{"className":192,"code":1331,"language":194,"meta":75,"style":75},"build:\n  stage: build\n  cache:\n    key: $CI_COMMIT_REF_SLUG\n    paths:\n      - node_modules\u002F\n      - .npm\u002F\n  script:\n    - npm ci --cache .npm --prefer-offline\n    - npm run build\n",[77,1333,1334,1340,1348,1355,1365,1372,1380,1387,1393,1400],{"__ignoreMap":75},[80,1335,1336,1338],{"class":82,"line":83},[80,1337,456],{"class":201},[80,1339,205],{"class":131},[80,1341,1342,1344,1346],{"class":82,"line":103},[80,1343,464],{"class":201},[80,1345,68],{"class":131},[80,1347,383],{"class":90},[80,1349,1350,1353],{"class":82,"line":113},[80,1351,1352],{"class":201},"  cache",[80,1354,205],{"class":131},[80,1356,1357,1360,1362],{"class":82,"line":135},[80,1358,1359],{"class":201},"    key",[80,1361,68],{"class":131},[80,1363,1364],{"class":90}," $CI_COMMIT_REF_SLUG\n",[80,1366,1367,1370],{"class":82,"line":148},[80,1368,1369],{"class":201},"    paths",[80,1371,205],{"class":131},[80,1373,1374,1377],{"class":82,"line":172},[80,1375,1376],{"class":217},"      -",[80,1378,1379],{"class":90}," node_modules\u002F\n",[80,1381,1382,1384],{"class":82,"line":316},[80,1383,1376],{"class":217},[80,1385,1386],{"class":90}," .npm\u002F\n",[80,1388,1389,1391],{"class":82,"line":327},[80,1390,501],{"class":201},[80,1392,205],{"class":131},[80,1394,1395,1397],{"class":82,"line":335},[80,1396,218],{"class":217},[80,1398,1399],{"class":90}," npm ci --cache .npm --prefer-offline\n",[80,1401,1402,1404],{"class":82,"line":437},[80,1403,218],{"class":217},[80,1405,1406],{"class":90}," npm run build\n",[37,1408,1410],{"id":1409},"dagdirected-acyclic-graphによる並列化","DAG（Directed Acyclic Graph）による並列化",[70,1412,1414],{"className":192,"code":1413,"language":194,"meta":75,"style":75},"stages:\n  - build\n  - test\n  - deploy\n\nlint:\n  stage: test\n  needs: []  # build を待たずに実行\n  script:\n    - npm run lint\n\nunit-test:\n  stage: test\n  needs: [\"build\"]\n  script:\n    - npm test\n\ne2e-test:\n  stage: test\n  needs: [\"build\"]\n  script:\n    - npm run e2e\n",[77,1415,1416,1422,1428,1434,1441,1445,1452,1460,1473,1479,1486,1490,1497,1505,1522,1528,1534,1538,1545,1553,1569,1575],{"__ignoreMap":75},[80,1417,1418,1420],{"class":82,"line":83},[80,1419,373],{"class":201},[80,1421,205],{"class":131},[80,1423,1424,1426],{"class":82,"line":103},[80,1425,380],{"class":217},[80,1427,383],{"class":90},[80,1429,1430,1432],{"class":82,"line":113},[80,1431,380],{"class":217},[80,1433,390],{"class":90},[80,1435,1436,1438],{"class":82,"line":135},[80,1437,380],{"class":217},[80,1439,1440],{"class":90}," deploy\n",[80,1442,1443],{"class":82,"line":148},[80,1444,417],{"emptyLinePlaceholder":416},[80,1446,1447,1450],{"class":82,"line":172},[80,1448,1449],{"class":201},"lint",[80,1451,205],{"class":131},[80,1453,1454,1456,1458],{"class":82,"line":316},[80,1455,464],{"class":201},[80,1457,68],{"class":131},[80,1459,390],{"class":90},[80,1461,1462,1465,1467,1470],{"class":82,"line":327},[80,1463,1464],{"class":201},"  needs",[80,1466,68],{"class":131},[80,1468,1469],{"class":131}," []",[80,1471,1472],{"class":1047},"  # build を待たずに実行\n",[80,1474,1475,1477],{"class":82,"line":335},[80,1476,501],{"class":201},[80,1478,205],{"class":131},[80,1480,1481,1483],{"class":82,"line":437},[80,1482,218],{"class":217},[80,1484,1485],{"class":90}," npm run lint\n",[80,1487,1488],{"class":82,"line":448},[80,1489,417],{"emptyLinePlaceholder":416},[80,1491,1492,1495],{"class":82,"line":453},[80,1493,1494],{"class":201},"unit-test",[80,1496,205],{"class":131},[80,1498,1499,1501,1503],{"class":82,"line":461},[80,1500,464],{"class":201},[80,1502,68],{"class":131},[80,1504,390],{"class":90},[80,1506,1507,1509,1511,1513,1516,1518,1520],{"class":82,"line":471},[80,1508,1464],{"class":201},[80,1510,68],{"class":131},[80,1512,633],{"class":131},[80,1514,1515],{"class":131},"\"",[80,1517,456],{"class":90},[80,1519,1515],{"class":131},[80,1521,639],{"class":131},[80,1523,1524,1526],{"class":82,"line":482},[80,1525,501],{"class":201},[80,1527,205],{"class":131},[80,1529,1530,1532],{"class":82,"line":490},[80,1531,218],{"class":217},[80,1533,582],{"class":90},[80,1535,1536],{"class":82,"line":498},[80,1537,417],{"emptyLinePlaceholder":416},[80,1539,1540,1543],{"class":82,"line":506},[80,1541,1542],{"class":201},"e2e-test",[80,1544,205],{"class":131},[80,1546,1547,1549,1551],{"class":82,"line":514},[80,1548,464],{"class":201},[80,1550,68],{"class":131},[80,1552,390],{"class":90},[80,1554,1555,1557,1559,1561,1563,1565,1567],{"class":82,"line":522},[80,1556,1464],{"class":201},[80,1558,68],{"class":131},[80,1560,633],{"class":131},[80,1562,1515],{"class":131},[80,1564,456],{"class":90},[80,1566,1515],{"class":131},[80,1568,639],{"class":131},[80,1570,1571,1573],{"class":82,"line":530},[80,1572,501],{"class":201},[80,1574,205],{"class":131},[80,1576,1577,1579],{"class":82,"line":535},[80,1578,218],{"class":217},[80,1580,1581],{"class":90}," npm run e2e\n",[11,1583,1584,1587,1588,1593],{},[77,1585,1586],{},"needs"," キーワードで ",[15,1589,1592],{"href":1590,"rel":1591},"https:\u002F\u002Fdocs.gitlab.com\u002Fci\u002Fdirected_acyclic_graph\u002F",[19],"DAG パイプライン"," を構築し、不要な待機時間を排除します。",[37,1595,1597],{"id":1596},"gitlab-runner-のスケーリング","GitLab Runner のスケーリング",[11,1599,1600,1605,1606,1609],{},[15,1601,1604],{"href":1602,"rel":1603},"https:\u002F\u002Faws.amazon.com\u002Fblogs\u002Fcontainers\u002Fstreamline-your-containerized-ci-cd-with-gitlab-runners-and-amazon-eks-auto-mode\u002F",[19],"Amazon EKS Auto Mode との統合","により、Spot インスタンスの活用で最大 90% のコスト削減が可能です。",[15,1607,20],{"href":17,"rel":1608},[19]," でも同様のランナー最適化が組み込まれています。",[23,1611,1613],{"id":1612},"まとめ-kubo-で-gitlab-ci-cd-を始めよう","まとめ: Kubo で GitLab ci-cd を始めよう",[11,1615,1616],{},"GitLab ci-cd は、統合 DevOps プラットフォームとしてコンテナデプロイの自動化に強力な機能を提供します。Kubernetes Agent によるセキュアな接続、Auto DevOps による自動パイプライン、Review Apps による動的環境など、エンタープライズグレードのデプロイフローを実現できます。",[11,1618,1619,1622,1623,1626,1627,1632],{},[15,1620,20],{"href":17,"rel":1621},[19]," は GitLab ci-cd との統合を標準サポートしており、Agent の設定からマルチ環境デプロイまで、スムーズに導入できます。",[15,1624,348],{"href":346,"rel":1625},[19]," の AI アシスタントがパイプラインの最適化を支援し、GitLab ci-cd の生産性をさらに引き上げます。コンテナデプロイの自動化に取り組みたい方は、ぜひ",[15,1628,1631],{"href":1629,"rel":1630},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[19],"お問い合わせ","ください。",[1634,1635,1636],"style",{},"html pre.shiki code .sE3pS, html code.shiki .sE3pS{--shiki-default:#C0CAF5}html pre.shiki code .sPY7s, html code.shiki .sPY7s{--shiki-default:#9ECE6A}html pre.shiki code .sT800, html code.shiki .sT800{--shiki-default:#E0AF68}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sGX4V, html code.shiki .sGX4V{--shiki-default:#A9B1D6}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);}html pre.shiki code .s0U2E, html code.shiki .s0U2E{--shiki-default:#F7768E}html pre.shiki code .sgJMe, html code.shiki .sgJMe{--shiki-default:#9ABDF5}html pre.shiki code .sbD-w, html code.shiki .sbD-w{--shiki-default:#51597D;--shiki-default-font-style:italic}html pre.shiki code .sOJ5S, html code.shiki .sOJ5S{--shiki-default:#FF9E64}",{"title":75,"searchDepth":103,"depth":103,"links":1638},[1639,1644,1648,1652,1656,1661],{"id":25,"depth":103,"text":26,"children":1640},[1641,1642,1643],{"id":39,"depth":113,"text":40},{"id":51,"depth":113,"text":52},{"id":250,"depth":113,"text":251},{"id":352,"depth":103,"text":353,"children":1645},[1646,1647],{"id":363,"depth":113,"text":363},{"id":882,"depth":113,"text":883},{"id":906,"depth":103,"text":907,"children":1649},[1650,1651],{"id":921,"depth":113,"text":922},{"id":1029,"depth":113,"text":1030},{"id":1074,"depth":103,"text":1074,"children":1653},[1654,1655],{"id":1080,"depth":113,"text":1080},{"id":1146,"depth":113,"text":1147},{"id":1325,"depth":103,"text":1325,"children":1657},[1658,1659,1660],{"id":1328,"depth":113,"text":1328},{"id":1409,"depth":113,"text":1410},{"id":1596,"depth":113,"text":1597},{"id":1612,"depth":103,"text":1613},"2026-05-27","GitLab ci-cd と Kubernetes Agent を使ったコンテナデプロイの自動化を実践解説。パイプライン構成、Auto DevOps、セキュリティ設定まで詳しく紹介。","md","ja",{},"\u002Fblog\u002Fja\u002Fgitlab-ci-container-deployment",{"title":5,"description":1663},"blog\u002Fja\u002Fgitlab-ci-container-deployment",[1671,1672,1673,1674,1675,1676],"GitLab","ci-cd","Kubernetes","コンテナ","Auto DevOps","デプロイ自動化","dAb3vPnZlUpJPwheneGqzqS0r-IwWtA4L4Pi5DaGQEs",1779964617053]