[{"data":1,"prerenderedAt":845},["ShallowReactive",2],{"/en-us/blog/tags/cd/":3,"navigation-ja-jp":20,"banner-ja-jp":437,"footer-ja-jp":450,"CD-tag-page-ja-jp":659},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"content":8,"config":11,"_id":13,"_type":14,"title":15,"_source":16,"_file":17,"_stem":18,"_extension":19},"/en-us/blog/tags/cd","tags",false,"",{"tag":9,"tagSlug":10},"CD","cd",{"template":12},"BlogTag","content:en-us:blog:tags:cd.yml","yaml","Cd","content","en-us/blog/tags/cd.yml","en-us/blog/tags/cd","yml",{"_path":21,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"data":23,"_id":433,"_type":14,"title":434,"_source":16,"_file":435,"_stem":436,"_extension":19},"/shared/ja-jp/main-navigation","ja-jp",{"logo":24,"freeTrial":29,"sales":34,"login":39,"items":44,"search":377,"minimal":411,"duo":424},{"config":25},{"href":26,"dataGaName":27,"dataGaLocation":28},"/ja-jp/","gitlab logo","header",{"text":30,"config":31},"無料トライアルを開始",{"href":32,"dataGaName":33,"dataGaLocation":28},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":35,"config":36},"お問い合わせ",{"href":37,"dataGaName":38,"dataGaLocation":28},"/ja-jp/sales/","sales",{"text":40,"config":41},"サインイン",{"href":42,"dataGaName":43,"dataGaLocation":28},"https://gitlab.com/users/sign_in/","sign in",[45,89,188,193,299,359],{"text":46,"config":47,"cards":49,"footer":72},"プラットフォーム",{"dataNavLevelOne":48},"platform",[50,56,64],{"title":46,"description":51,"link":52},"最も包括的かつAIで強化されたDevSecOpsプラットフォーム",{"text":53,"config":54},"プラットフォームを詳しく見る",{"href":55,"dataGaName":48,"dataGaLocation":28},"/ja-jp/platform/",{"title":57,"description":58,"link":59},"GitLab Duo（AI）","開発のすべてのステージでAIを活用し、ソフトウェアをより迅速にビルド",{"text":60,"config":61},"GitLab Duoのご紹介",{"href":62,"dataGaName":63,"dataGaLocation":28},"/ja-jp/gitlab-duo/","gitlab duo ai",{"title":65,"description":66,"link":67},"GitLabが選ばれる理由","GitLabが大企業に選ばれる理由10選",{"text":68,"config":69},"詳細はこちら",{"href":70,"dataGaName":71,"dataGaLocation":28},"/ja-jp/why-gitlab/","why gitlab",{"title":73,"items":74},"利用を開始：",[75,80,85],{"text":76,"config":77},"プラットフォームエンジニアリング",{"href":78,"dataGaName":79,"dataGaLocation":28},"/ja-jp/solutions/platform-engineering/","platform engineering",{"text":81,"config":82},"開発者の経験",{"href":83,"dataGaName":84,"dataGaLocation":28},"/ja-jp/developer-experience/","Developer experience",{"text":86,"config":87},"MLOps",{"href":88,"dataGaName":86,"dataGaLocation":28},"/ja-jp/topics/devops/the-role-of-ai-in-devops/",{"text":90,"left":91,"config":92,"link":94,"lists":98,"footer":170},"製品",true,{"dataNavLevelOne":93},"solutions",{"text":95,"config":96},"すべてのソリューションを表示",{"href":97,"dataGaName":93,"dataGaLocation":28},"/ja-jp/solutions/",[99,125,148],{"title":100,"description":101,"link":102,"items":107},"自動化","CI/CDと自動化でデプロイを加速",{"config":103},{"icon":104,"href":105,"dataGaName":106,"dataGaLocation":28},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[108,112,116,121],{"text":109,"config":110},"CI/CD",{"href":111,"dataGaLocation":28,"dataGaName":109},"/ja-jp/solutions/continuous-integration/",{"text":113,"config":114},"AIアシストによる開発",{"href":62,"dataGaLocation":28,"dataGaName":115},"AI assisted development",{"text":117,"config":118},"ソースコード管理",{"href":119,"dataGaLocation":28,"dataGaName":120},"/ja-jp/solutions/source-code-management/","Source Code Management",{"text":122,"config":123},"自動化されたソフトウェアデリバリー",{"href":105,"dataGaLocation":28,"dataGaName":124},"Automated software delivery",{"title":126,"description":127,"link":128,"items":133},"セキュリティ","セキュリティを損なうことなくコードをより迅速に完成",{"config":129},{"href":130,"dataGaName":131,"dataGaLocation":28,"icon":132},"/ja-jp/solutions/security-compliance/","security and compliance","ShieldCheckLight",[134,139,144],{"text":135,"config":136},"Application Security Testing",{"href":137,"dataGaName":138,"dataGaLocation":28},"/solutions/application-security-testing/","Application security testing",{"text":140,"config":141},"ソフトウェアサプライチェーンの安全性",{"href":142,"dataGaLocation":28,"dataGaName":143},"/ja-jp/solutions/supply-chain/","Software supply chain security",{"text":145,"config":146},"Software Compliance",{"href":147,"dataGaName":145,"dataGaLocation":28},"/solutions/software-compliance/",{"title":149,"link":150,"items":155},"測定",{"config":151},{"icon":152,"href":153,"dataGaName":154,"dataGaLocation":28},"DigitalTransformation","/ja-jp/solutions/visibility-measurement/","visibility and measurement",[156,160,165],{"text":157,"config":158},"可視性と測定",{"href":153,"dataGaLocation":28,"dataGaName":159},"Visibility and Measurement",{"text":161,"config":162},"バリューストリーム管理",{"href":163,"dataGaLocation":28,"dataGaName":164},"/ja-jp/solutions/value-stream-management/","Value Stream Management",{"text":166,"config":167},"分析とインサイト",{"href":168,"dataGaLocation":28,"dataGaName":169},"/ja-jp/solutions/analytics-and-insights/","Analytics and insights",{"title":171,"items":172},"GitLabが活躍する場所",[173,178,183],{"text":174,"config":175},"Enterprise",{"href":176,"dataGaLocation":28,"dataGaName":177},"/ja-jp/enterprise/","enterprise",{"text":179,"config":180},"スモールビジネス",{"href":181,"dataGaLocation":28,"dataGaName":182},"/ja-jp/small-business/","small business",{"text":184,"config":185},"公共機関",{"href":186,"dataGaLocation":28,"dataGaName":187},"/ja-jp/solutions/public-sector/","public sector",{"text":189,"config":190},"価格",{"href":191,"dataGaName":192,"dataGaLocation":28,"dataNavLevelOne":192},"/ja-jp/pricing/","pricing",{"text":194,"config":195,"link":197,"lists":201,"feature":286},"関連リソース",{"dataNavLevelOne":196},"resources",{"text":198,"config":199},"すべてのリソースを表示",{"href":200,"dataGaName":196,"dataGaLocation":28},"/ja-jp/resources/",[202,235,258],{"title":203,"items":204},"はじめに",[205,210,215,220,225,230],{"text":206,"config":207},"インストール",{"href":208,"dataGaName":209,"dataGaLocation":28},"/ja-jp/install/","install",{"text":211,"config":212},"クイックスタートガイド",{"href":213,"dataGaName":214,"dataGaLocation":28},"/ja-jp/get-started/","quick setup checklists",{"text":216,"config":217},"学ぶ",{"href":218,"dataGaLocation":28,"dataGaName":219},"https://university.gitlab.com/","learn",{"text":221,"config":222},"製品ドキュメント",{"href":223,"dataGaName":224,"dataGaLocation":28},"https://docs.gitlab.com/","product documentation",{"text":226,"config":227},"ベストプラクティスビデオ",{"href":228,"dataGaName":229,"dataGaLocation":28},"/ja-jp/getting-started-videos/","best practice videos",{"text":231,"config":232},"インテグレーション",{"href":233,"dataGaName":234,"dataGaLocation":28},"/ja-jp/integrations/","integrations",{"title":236,"items":237},"検索する",[238,243,248,253],{"text":239,"config":240},"お客様成功事例",{"href":241,"dataGaName":242,"dataGaLocation":28},"/ja-jp/customers/","customer success stories",{"text":244,"config":245},"ブログ",{"href":246,"dataGaName":247,"dataGaLocation":28},"/ja-jp/blog/","blog",{"text":249,"config":250},"リモート",{"href":251,"dataGaName":252,"dataGaLocation":28},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":254,"config":255},"TeamOps",{"href":256,"dataGaName":257,"dataGaLocation":28},"/ja-jp/teamops/","teamops",{"title":259,"items":260},"つなげる",[261,266,271,276,281],{"text":262,"config":263},"GitLabサービス",{"href":264,"dataGaName":265,"dataGaLocation":28},"/ja-jp/services/","services",{"text":267,"config":268},"コミュニティ",{"href":269,"dataGaName":270,"dataGaLocation":28},"/community/","community",{"text":272,"config":273},"フォーラム",{"href":274,"dataGaName":275,"dataGaLocation":28},"https://forum.gitlab.com/","forum",{"text":277,"config":278},"イベント",{"href":279,"dataGaName":280,"dataGaLocation":28},"/events/","events",{"text":282,"config":283},"パートナー",{"href":284,"dataGaName":285,"dataGaLocation":28},"/partners/","partners",{"backgroundColor":287,"textColor":288,"text":289,"image":290,"link":294},"#2f2a6b","#fff","ソフトウェア開発の未来への洞察",{"altText":291,"config":292},"ソースプロモカード",{"src":293},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":295,"config":296},"最新情報を読む",{"href":297,"dataGaName":298,"dataGaLocation":28},"/ja-jp/the-source/","the source",{"text":300,"config":301,"lists":303},"Company",{"dataNavLevelOne":302},"company",[304],{"items":305},[306,311,317,319,324,329,334,339,344,349,354],{"text":307,"config":308},"GitLabについて",{"href":309,"dataGaName":310,"dataGaLocation":28},"/ja-jp/company/","about",{"text":312,"config":313,"footerGa":316},"採用情報",{"href":314,"dataGaName":315,"dataGaLocation":28},"/jobs/","jobs",{"dataGaName":315},{"text":277,"config":318},{"href":279,"dataGaName":280,"dataGaLocation":28},{"text":320,"config":321},"経営陣",{"href":322,"dataGaName":323,"dataGaLocation":28},"/company/team/e-group/","leadership",{"text":325,"config":326},"チーム",{"href":327,"dataGaName":328,"dataGaLocation":28},"/company/team/","team",{"text":330,"config":331},"ハンドブック",{"href":332,"dataGaName":333,"dataGaLocation":28},"https://handbook.gitlab.com/","handbook",{"text":335,"config":336},"投資家向け情報",{"href":337,"dataGaName":338,"dataGaLocation":28},"https://ir.gitlab.com/","investor relations",{"text":340,"config":341},"トラストセンター",{"href":342,"dataGaName":343,"dataGaLocation":28},"/ja-jp/security/","trust center",{"text":345,"config":346},"AI Transparency Center",{"href":347,"dataGaName":348,"dataGaLocation":28},"/ja-jp/ai-transparency-center/","ai transparency center",{"text":350,"config":351},"ニュースレター",{"href":352,"dataGaName":353,"dataGaLocation":28},"/company/contact/","newsletter",{"text":355,"config":356},"プレス",{"href":357,"dataGaName":358,"dataGaLocation":28},"/press/","press",{"text":35,"config":360,"lists":361},{"dataNavLevelOne":302},[362],{"items":363},[364,367,372],{"text":35,"config":365},{"href":37,"dataGaName":366,"dataGaLocation":28},"talk to sales",{"text":368,"config":369},"サポートを受ける",{"href":370,"dataGaName":371,"dataGaLocation":28},"/support/","get help",{"text":373,"config":374},"カスタマーポータル",{"href":375,"dataGaName":376,"dataGaLocation":28},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":378,"login":379,"suggestions":386},"閉じる",{"text":380,"link":381},"リポジトリとプロジェクトを検索するには、次にログインします",{"text":382,"config":383},"GitLab.com",{"href":42,"dataGaName":384,"dataGaLocation":385},"search login","search",{"text":387,"default":388},"提案",[389,392,397,399,403,407],{"text":57,"config":390},{"href":62,"dataGaName":391,"dataGaLocation":385},"GitLab Duo (AI)",{"text":393,"config":394},"コード提案（AI）",{"href":395,"dataGaName":396,"dataGaLocation":385},"/ja-jp/solutions/code-suggestions/","Code Suggestions (AI)",{"text":109,"config":398},{"href":111,"dataGaName":109,"dataGaLocation":385},{"text":400,"config":401},"GitLab on AWS",{"href":402,"dataGaName":400,"dataGaLocation":385},"/ja-jp/partners/technology-partners/aws/",{"text":404,"config":405},"GitLab on Google Cloud",{"href":406,"dataGaName":404,"dataGaLocation":385},"/ja-jp/partners/technology-partners/google-cloud-platform/",{"text":408,"config":409},"GitLabを選ぶ理由",{"href":70,"dataGaName":410,"dataGaLocation":385},"Why GitLab?",{"freeTrial":412,"mobileIcon":416,"desktopIcon":421},{"text":30,"config":413},{"href":414,"dataGaName":33,"dataGaLocation":415},"https://gitlab.com/-/trials/new/","nav",{"altText":417,"config":418},"GitLabアイコン",{"src":419,"dataGaName":420,"dataGaLocation":415},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":417,"config":422},{"src":423,"dataGaName":420,"dataGaLocation":415},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"freeTrial":425,"mobileIcon":429,"desktopIcon":431},{"text":426,"config":427},"GitLab Duoの詳細について",{"href":62,"dataGaName":428,"dataGaLocation":415},"gitlab duo",{"altText":417,"config":430},{"src":419,"dataGaName":420,"dataGaLocation":415},{"altText":417,"config":432},{"src":423,"dataGaName":420,"dataGaLocation":415},"content:shared:ja-jp:main-navigation.yml","Main Navigation","shared/ja-jp/main-navigation.yml","shared/ja-jp/main-navigation",{"_path":438,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"title":439,"button":440,"config":445,"_id":447,"_type":14,"_source":16,"_file":448,"_stem":449,"_extension":19},"/shared/ja-jp/banner","GitLab Duo Agent Platformがパブリックベータ版で利用可能になりました！",{"text":441,"config":442},"ベータ版を試す",{"href":443,"dataGaName":444,"dataGaLocation":28},"/ja-jp/gitlab-duo/agent-platform/","duo banner",{"layout":446},"release","content:shared:ja-jp:banner.yml","shared/ja-jp/banner.yml","shared/ja-jp/banner",{"_path":451,"_dir":22,"_draft":6,"_partial":6,"_locale":7,"data":452,"_id":655,"_type":14,"title":656,"_source":16,"_file":657,"_stem":658,"_extension":19},"/shared/ja-jp/main-footer",{"text":453,"source":454,"edit":460,"contribute":465,"config":470,"items":475,"minimal":647},"GitはSoftware Freedom Conservancyの商標です。当社は「GitLab」をライセンスに基づいて使用しています",{"text":455,"config":456},"ページのソースを表示",{"href":457,"dataGaName":458,"dataGaLocation":459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":461,"config":462},"このページを編集",{"href":463,"dataGaName":464,"dataGaLocation":459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":466,"config":467},"ご協力をお願いします",{"href":468,"dataGaName":469,"dataGaLocation":459},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":471,"facebook":472,"youtube":473,"linkedin":474},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[476,499,553,585,619],{"title":46,"links":477,"subMenu":482},[478],{"text":479,"config":480},"DevSecOpsプラットフォーム",{"href":55,"dataGaName":481,"dataGaLocation":459},"devsecops platform",[483],{"title":189,"links":484},[485,489,494],{"text":486,"config":487},"プランの表示",{"href":191,"dataGaName":488,"dataGaLocation":459},"view plans",{"text":490,"config":491},"Premiumを選ぶ理由",{"href":492,"dataGaName":493,"dataGaLocation":459},"/ja-jp/pricing/premium/","why premium",{"text":495,"config":496},"Ultimateを選ぶ理由",{"href":497,"dataGaName":498,"dataGaLocation":459},"/ja-jp/pricing/ultimate/","why ultimate",{"title":500,"links":501},"ソリューション",[502,507,510,512,517,522,526,529,532,537,539,541,543,548],{"text":503,"config":504},"デジタルトランスフォーメーション",{"href":505,"dataGaName":506,"dataGaLocation":459},"/ja-jp/topics/digital-transformation/","digital transformation",{"text":508,"config":509},"セキュリティとコンプライアンス",{"href":137,"dataGaName":138,"dataGaLocation":459},{"text":122,"config":511},{"href":105,"dataGaName":106,"dataGaLocation":459},{"text":513,"config":514},"アジャイル開発",{"href":515,"dataGaName":516,"dataGaLocation":459},"/ja-jp/solutions/agile-delivery/","agile delivery",{"text":518,"config":519},"クラウドトランスフォーメーション",{"href":520,"dataGaName":521,"dataGaLocation":459},"/ja-jp/topics/cloud-native/","cloud transformation",{"text":523,"config":524},"SCM",{"href":119,"dataGaName":525,"dataGaLocation":459},"source code management",{"text":109,"config":527},{"href":111,"dataGaName":528,"dataGaLocation":459},"continuous integration & delivery",{"text":161,"config":530},{"href":163,"dataGaName":531,"dataGaLocation":459},"value stream management",{"text":533,"config":534},"GitOps",{"href":535,"dataGaName":536,"dataGaLocation":459},"/ja-jp/solutions/gitops/","gitops",{"text":174,"config":538},{"href":176,"dataGaName":177,"dataGaLocation":459},{"text":179,"config":540},{"href":181,"dataGaName":182,"dataGaLocation":459},{"text":184,"config":542},{"href":186,"dataGaName":187,"dataGaLocation":459},{"text":544,"config":545},"教育",{"href":546,"dataGaName":547,"dataGaLocation":459},"/ja-jp/solutions/education/","education",{"text":549,"config":550},"金融サービス",{"href":551,"dataGaName":552,"dataGaLocation":459},"/ja-jp/solutions/finance/","financial services",{"title":194,"links":554},[555,557,559,561,564,566,569,571,573,575,577,579,581,583],{"text":206,"config":556},{"href":208,"dataGaName":209,"dataGaLocation":459},{"text":211,"config":558},{"href":213,"dataGaName":214,"dataGaLocation":459},{"text":216,"config":560},{"href":218,"dataGaName":219,"dataGaLocation":459},{"text":221,"config":562},{"href":223,"dataGaName":563,"dataGaLocation":459},"docs",{"text":244,"config":565},{"href":246,"dataGaName":247},{"text":567,"config":568},"お客様の成功事例",{"href":241,"dataGaLocation":459},{"text":239,"config":570},{"href":241,"dataGaName":242,"dataGaLocation":459},{"text":249,"config":572},{"href":251,"dataGaName":252,"dataGaLocation":459},{"text":262,"config":574},{"href":264,"dataGaName":265,"dataGaLocation":459},{"text":254,"config":576},{"href":256,"dataGaName":257,"dataGaLocation":459},{"text":267,"config":578},{"href":269,"dataGaName":270,"dataGaLocation":459},{"text":272,"config":580},{"href":274,"dataGaName":275,"dataGaLocation":459},{"text":277,"config":582},{"href":279,"dataGaName":280,"dataGaLocation":459},{"text":282,"config":584},{"href":284,"dataGaName":285,"dataGaLocation":459},{"title":300,"links":586},[587,589,591,593,595,597,599,603,608,610,612,614],{"text":307,"config":588},{"href":309,"dataGaName":302,"dataGaLocation":459},{"text":312,"config":590},{"href":314,"dataGaName":315,"dataGaLocation":459},{"text":320,"config":592},{"href":322,"dataGaName":323,"dataGaLocation":459},{"text":325,"config":594},{"href":327,"dataGaName":328,"dataGaLocation":459},{"text":330,"config":596},{"href":332,"dataGaName":333,"dataGaLocation":459},{"text":335,"config":598},{"href":337,"dataGaName":338,"dataGaLocation":459},{"text":600,"config":601},"Sustainability",{"href":602,"dataGaName":600,"dataGaLocation":459},"/sustainability/",{"text":604,"config":605},"ダイバーシティ、インクルージョン、ビロンギング（DIB）",{"href":606,"dataGaName":607,"dataGaLocation":459},"/ja-jp/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":340,"config":609},{"href":342,"dataGaName":343,"dataGaLocation":459},{"text":350,"config":611},{"href":352,"dataGaName":353,"dataGaLocation":459},{"text":355,"config":613},{"href":357,"dataGaName":358,"dataGaLocation":459},{"text":615,"config":616},"現代奴隷制の透明性に関する声明",{"href":617,"dataGaName":618,"dataGaLocation":459},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":35,"links":620},[621,623,625,627,632,637,642],{"text":35,"config":622},{"href":37,"dataGaName":38,"dataGaLocation":459},{"text":368,"config":624},{"href":370,"dataGaName":371,"dataGaLocation":459},{"text":373,"config":626},{"href":375,"dataGaName":376,"dataGaLocation":459},{"text":628,"config":629},"ステータス",{"href":630,"dataGaName":631,"dataGaLocation":459},"https://status.gitlab.com/","status",{"text":633,"config":634},"利用規約",{"href":635,"dataGaName":636,"dataGaLocation":459},"/terms/","terms of use",{"text":638,"config":639},"プライバシーに関する声明",{"href":640,"dataGaName":641,"dataGaLocation":459},"/ja-jp/privacy/","privacy statement",{"text":643,"config":644},"Cookieの設定",{"dataGaName":645,"dataGaLocation":459,"id":646,"isOneTrustButton":91},"cookie preferences","ot-sdk-btn",{"items":648},[649,651,653],{"text":633,"config":650},{"href":635,"dataGaName":636,"dataGaLocation":459},{"text":638,"config":652},{"href":640,"dataGaName":641,"dataGaLocation":459},{"text":643,"config":654},{"dataGaName":645,"dataGaLocation":459,"id":646,"isOneTrustButton":91},"content:shared:ja-jp:main-footer.yml","Main Footer","shared/ja-jp/main-footer.yml","shared/ja-jp/main-footer",{"allPosts":660,"featuredPost":821,"totalPagesCount":843,"initialPosts":844},[661,690,714,737,758,777,800],{"_path":662,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":663,"content":671,"config":683,"_id":686,"_type":14,"title":687,"_source":16,"_file":688,"_stem":689,"_extension":19},"/ja-jp/blog/demystifying-ci-cd-variables",{"title":664,"description":665,"ogTitle":664,"ogDescription":665,"noIndex":6,"ogImage":666,"ogUrl":667,"ogSiteName":668,"ogType":669,"canonicalUrls":667,"schema":670},"GitLabの環境変数をわかりやすく解説","CI/CD変数はジョブやパイプラインを制御するのに便利（かつ柔軟に利用可能）なツールです。この記事では、GitLabの環境変数について知っておくべき情報をすべてご紹介します。","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664679/Blog/Hero%20Images/blog-image-template-1800x945__24_.png","https://about.gitlab.com/blog/demystifying-ci-cd-variables","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLabの環境変数をわかりやすく解説\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Veethika Mishra\"}],\n        \"datePublished\": \"2021-04-09\",\n      }",{"title":664,"description":665,"authors":672,"heroImage":666,"date":674,"body":675,"category":676,"tags":677,"updatedDate":682},[673],"Veethika Mishra","2021-04-09","[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)変数は、さまざまな方法で定義・使用でき、高い柔軟性を持っています。変数はジョブやパイプラインを制御する上で非常に便利で、`.gitlab-ci.yml`設定ファイルに値をハードコーディングせずに済みます。このブログ記事では、変数のスコープや機能を分かりやすくお伝えするため、変数の定義や使い方に関する情報を網羅的に整理し、全体像をご紹介します。記事全体をとおして、関連するドキュメントがリンクされています。\n\n\n[GitLab\nCI/CD](https://docs.gitlab.com/ee/ci/)では、値を定義して保存することで、変数を使用してジョブをカスタマイズできます。変数を使用すれば、値をハードコーディングする必要はありません。GitLabでCI/CD変数を定義するには、**「設定」>>「CI/CD」>>「変数」**の順に移動します。または`.gitlab-ci.yml`ファイルで定義することも可能です。\n\n\n変数は、異なるデプロイ環境（`testing`、`staging`、`production`など）におけるサードパーティサービスの設定に役立ちます。それらの環境に紐づけられたサービスは、必要なAPIエンドポイントを指す変数を変更するだけで、簡単に変更できます。また、変数を使用してジョブを設定し、ジョブ実行時にジョブ内で環境変数として利用できるようにすることも可能です。\n\n\n![GitLabは、.gitlab-ci.ymlファイルを読み込んで、参照される変数をスキャンし、GitLab\nRunnerにその情報を送信します。変数情報はRunnerに渡され、Runnerによって出力されます。](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_processing.jpeg)\n\n\n## 変数と環境の関係\n\n\nソフトウェア開発プロセスには、製品をユーザー向けにリリースする前にテストするステージが含まれます。[環境](https://docs.gitlab.com/ee/ci/environments/)は、これらのステージの内容を定義するために使用されるもので、チームや組織によって異なる可能性があります。\n\n\n一方、変数とは、ユーザーによる製品の操作によって変化する可能性のあるデータ値を指します。これには、年齢や好み、またはタスクフローにおける次のステップを決定する要素となるあらゆる入力が該当します。\n\n\n[環境変数](https://docs.gitlab.com/ee/administration/environment_variables.html)という言葉は、皆さんもよく耳にされると思います。これは、ある環境で定義されているものの、アプリケーションの外部に存在する変数を指します。GitLab\nCI/CD変数を使用すると、デベロッパーはコード内で値を設定できます。変数の使用には、コードの柔軟性が保証されるという利点があります。GitLab\nCI/CD変数を使用すれば、コードに変更を加えることなく、特定の環境にデプロイされたアプリケーションを変更できます。これにより、アプリケーションの外部で設定の環境変数を変更するだけで、テストの実行やサードパーティサービスの統合を簡単に行えます。\n\n\n## CI/CD変数のスコープ\n\n\n![CI/CD変数の優先順位：1) 手動によって実行、トリガー、スケジュールされたパイプライン変数、2)\nプロジェクトレベル、グループレベル、インスタンスレベルの保護変数、3) 継承されたCI/CD変数、4)\nymlに定義された、ジョブレベルのグローバル変数、5) デプロイ変数、6)\n定義済みのCI/CD変数](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_precedence.jpeg)\n\n\n### `.gitlab-ci.yml`に定義された変数\n\n\nGitLabには、ジョブ環境で利用する必要がある変数を追加できます。これらのCI/CD変数は、`.gitlab-ci.yml`ファイルのデータベースURLのような、機密性の低いプロジェクト設定を保存するために使用されます。この変数は、複数のジョブやスクリプトで再利用でき、必要な場所で値を参照できます。値を変更する場合は、変数を一度更新するだけで、変数が使用されているすべての箇所に変更が反映されます。\n\n\n### プロジェクトのCI/CD変数\n\n\nリポジトリ固有の要件に縛られることなく、[プロジェクト設定](https://docs.gitlab.com/ee/ci/variables/#for-a-project)でCI/CD変数を定義できます。これにより、CI/CDパイプラインで利用できるようになります。これらの変数は、リポジトリの外部（`.gitlab-ci.yml`ファイルには保存されません）に保存されますが、CI/CDの設定やスクリプトで引き続き利用可能です。変数を`.gitlab-ci.yml`ファイル外に保存することで、これらの値のスコープをプロジェクト内のみに限定し、プロジェクトにプレーンテキストとして保存されることを防ぎます。\n\n\n### グループおよびインスタンスのCI/CD変数\n\n\n一部の変数は、グループレベル、あるいはインスタンスレベルで適用でき、グループやインスタンス内のすべてのプロジェクトで有用となる可能性があります。[グループまたはインスタンス設定](https://docs.gitlab.com/ee/ci/variables/#for-a-group)で変数を定義することで、それらのスコープ内にあるすべてのプロジェクトにおいて、実際の値がわからなくても、変数を使用できるようになります。下位スコープの変数を作成する必要もありません。たとえば、複数のプロジェクトにおいて更新が必要な共通の値がある場合、1か所で最新の状態に保つことで管理しやすくなります。また、パスワードの値を実際に知らなくても、複数のプロジェクトで特定のパスワードを使用することも可能です。\n\n\n## 環境としてのジョブとパイプライン\n\n\nGitLab\nCI/CDの変数は、環境変数としてだけでなく、`.gitlab-ci.yml`設定ファイル内でパイプラインの動作を設定するためにも使用されます。この場合、特定の環境に依存しない状況でも利用できます。また、プロジェクト、グループ、インスタンスの設定に保存しておくことで、パイプライン内のジョブで利用可能になります。\n\n\n以下に例を示します。\n\n\n```  \n\njob:  \n  rules:  \n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH  \n  script:  \n  - echo \"This job ran on the $CI_COMMIT_BRANCH branch.\"  \n```\n\n\nスクリプトセクション内で使用されている変数（例：`$CI_COMMIT_BRANCH`）は、定義されたジョブのスコープ内で実行されます。このスコープは「ジョブ環境」と呼ばれます。つまり、ジョブが開始されると、GitLab\nRunnerはDockerコンテナを起動し、その環境でジョブを実行します。Runnerはその変数（および他のすべての定義済み変数やカスタム変数）をジョブに提供します。さらに、その値をログ出力に表示することも可能です。\n\n\nただし、この変数は、ジョブの実行タイミングを決定するために、`if:`セクション**でも**使用されます。ただし、そのセクション自体は環境ではないため、これらの変数を「CI/CD変数」と呼びます。CI/CDジョブを動的に設定する際に使用できるのは**もちろん**、ジョブの実行時に環境変数としても利用できます。\n\n\n## 定義済み変数\n\n\nGitLab\nCI/CDパイプラインが開始されたタイミングで、[定義済み変数](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)がすでに存在します。ユーザーは変数自体を定義せずに、コミットやプロジェクト、パイプラインの詳細などの値にすぐにアクセスできます。\n\n\n## カスタムCI/CD変数\n\n\n![Runnerは、2種類のカスタムCI/CD変数（タイプとファイル）を作成できます。](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variable_types.jpeg)\n\n\nGitLabでは、設定でCI/CD変数を作成する際に、変数に対してより詳細な設定オプションを利用できます。次のような追加の設定オプションを使用して、機密性の高い変数をより厳密に管理することが可能です。\n\n\n**環境スコープ**：ある変数を特定の環境でのみ使用する必要がある場合に、その環境でのみ使用できるように設定します。たとえば、デプロイトークンを`production`環境でのみ使用できるように設定できます。\n\n\n**保護変数**：環境スコープと同様に、デフォルトブランチなどの保護ブランチでパイプラインが実行される場合にのみ、変数を使用できるように設定できます。\n\n\n**変数タイプ**：一部のアプリケーションでは、設定をファイル形式で渡す必要があります。そうした設定が必要なアプリケーションを利用する場合は、変数タイプを「File」に設定します。この方法でCI/CD変数を設定する場合、Runnerが環境内で変数を利用できるようにする際に、実際に一時ファイルに変数を書き出し、そのファイルパスを変数の値として保存します。その後、アプリケーションに必要なファイルパスを渡すことで設定が適用されます。\n\n\nご紹介した変数の定義方法や使用方法に加えて、GitLabでは、手動でパイプラインを実行する必要がある場合に、事前入力済みの変数を生成する機能が導入されました。事前入力済みの変数が生成されることで、エラーの発生リスクが軽減され、パイプラインを実行しやすくなります。\n\n\n**マスクされた変数**：[マスクされた変数](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable)は、変数の値が表示されないように**ジョブログに隠された**CI変数です。\n\n\n**マスクおよび非表示化された変数**：[GitLab\n17.4](https://about.gitlab.com/ja-jp/blog/gitlab-17-4-released/)で導入された[マスクおよび非表示化された](https://docs.gitlab.com/ee/ci/variables/#hide-a-cicd-variable)変数は、ジョブログと同じマスキング機能を利用し、**設定UI**でも**値を非表示**にします。これらの変数を機密データ（シークレットなど）に使用した場合、誤って公開されてしまう可能性があるため、推奨されません。\n\n\n## シークレット\n\n\nシークレットとは、機密性が高く、秘密に保つべき認証情報のことを指し、以下のようなものが該当します。\n\n\n* パスワード\n\n* SSH鍵\n\n* アクセストークン\n\n* その他、漏洩すると組織に害を及ぼす可能性のある認証情報\n\n\nGitLabでは現在、キーやトークン、その他のシークレットをプロジェクトレベルで安全に管理するために、HashiCorp Vault、Google\nCloud Secret Manager、Azure Key\nVaultを活用できます。これにより、[CIで外部シークレットを使用](https://docs.gitlab.com/ee/ci/secrets/)することが可能です。そのため、セキュリティ上の理由から、これらのシークレットを他のCI/CD変数から分離して管理できます。\n\n\n### GitLabシークレットマネージャー\n\n\nGitLabでは、CIにおける外部シークレットのサポートに加えて、GitLab内でシークレットを安全かつ便利に保存するための[ネイティブなシークレット管理ソリューション](https://gitlab.com/groups/gitlab-org/-/epics/10108)の導入にも取り組んでいます。このソリューションは、お客様がGitLab固有のコンポーネントや環境で保存されたシークレットを使用したり、ネームスペースグループやプロジェクトレベルでのアクセスを簡単に管理したりする上でも役立ちます。\n\n\n## 関連リンク\n\n*\n[GitLabネイティブシークレットマネージャーでソフトウェアサプライチェーンのセキュリティを強化](https://about.gitlab.com/blog/gitlab-native-secrets-manager-to-give-software-supply-chain-security-a-boost/)\n\n\n***免責事項**：このブログには、今後リリース予定の製品、機能、および機能性に関する情報が記載されています。ただし、それらの情報はあくまで参考のために提供されているため、購入や計画の判断材料として使用することはお控えください。すべてのプロジェクトと同様に、このブログおよびリンク先のページに記載されている項目は、変更または遅延される場合があります。製品、機能、機能性の開発、リリース、およびタイミングに関する決定権は、GitLabに帰属します。*\n","engineering",[9,678,679,680,109,681],"features","inside GitLab","CI","tutorial","2025-01-13",{"slug":684,"featured":6,"template":685},"demystifying-ci-cd-variables","BlogPost","content:ja-jp:blog:demystifying-ci-cd-variables.yml","Demystifying Ci Cd Variables","ja-jp/blog/demystifying-ci-cd-variables.yml","ja-jp/blog/demystifying-ci-cd-variables",{"_path":691,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":692,"content":699,"config":708,"_id":710,"_type":14,"title":711,"_source":16,"_file":712,"_stem":713,"_extension":19},"/ja-jp/blog/ensuring-compliance",{"ogTitle":693,"schema":694,"ogImage":695,"ogDescription":696,"ogSiteName":668,"noIndex":6,"ogType":697,"ogUrl":698,"title":693,"canonicalUrls":698,"description":696},"GitLabで職務分離を実現し、コンプライアンスを遵守する方法","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLabで職務分離を実現し、コンプライアンスを遵守する方法\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Beatriz Barbosa\"},{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2022-04-04\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098232/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_479904468%20%281%29_4lmOEVlaXP0YC3hSFmOw6i_1750098232241.jpg","DevSecOpsプラットフォームを使用して開発速度を保ったまま、コンプライアンスを遵守しましょう。","記事","https://about.gitlab.com/blog/ensuring-compliance",{"heroImage":695,"body":700,"authors":701,"updatedDate":704,"date":705,"title":693,"tags":706,"description":696,"category":707},"この記事では、GitLab DevSecOpsプラットフォームを使用して**職務分離**と\n\n**継続的なコンプライアンス**を実現するためのさまざまな方法についてご紹介します。まずは、2つの重要な概念について説明しましょう。\n\n\n**コンプライアンス**とは、企業や政府機関などが定めたガイドラインや規格に則って\n\n行動することです。コンプライアンスは、\n\n企業倫理や適切なユーザーポリシー、セキュリティ基準などを守り、\n\n消費者の安全を確保する上で役立ちます。\n\n\nコンプライアンスに違反した場合、裁判費用や罰金が発生する可能性があります。そのため、コンプライアンスを維持することは非常に重要です。DevSecOpsチームはコンプライアンスを遵守しつつ開発速度を維持し、さらにシンプルさや可視性、制御といった要件も満たす必要があります。\n\n\n**職務分離**とは、エラーの防止や不正行為の抑止を目的に、業務を複数の担当者で分担することです。職務分離を行うことで、その作業に最適な担当者が作業を実施する体制となります。たとえば以下のように、\n\nそれぞれの担当者が特定の目的のもとで業務を受け持ちます。\n\n\n* デベロッパーは新機能の開発を担当\n\n* コンプライアンス担当者はパイプラインの作成と使用の実施を担当\n\n* アプリケーションセキュリティエンジニアは脆弱性のあるマージリクエストの承認を担当\n\n\nこのように業務が分担されていれば、たとえばデベロッパーが実行中のパイプラインを変更することはできません。\n\nそのような業務を行えるのはコンプライアンス担当者のみであり、承認なしでプッシュできるのはコンプライアンスに準拠しているコードのみであることが保証されます。\n\n\n脆弱性のあるコードのレビューと承認を担当するアプリケーションセキュリティエンジニアは、適切な方法で脆弱性を軽減し、将来的に問題が発生しないようにします。このシナリオでは、コンプライアンス\n\nとセキュリティの要件が満たされるまでデベロッパーはコードをマージできません。\n\n\n## セキュリティポリシー\n\n\nGitLabの**セキュリティポリシー**を使用すれば、セキュリティチームは設定に従ってセキュリティスキャンが必ず実行されるように指定できます。これにより、セキュリティチームは、設定済みのスキャンが変更されたり無効化されたりしていないことを把握できます。\n\n\nセキュリティポリシーは、特定の**コンプライアンスフレームワーク**を満たすようにスコープを設定できます。この場合、プロジェクトには特定のコンプライアンス要件が適用されているため、追加で監視を行う必要があります。このラベルは、トップレベルグループの **「セキュア」>「コンプライアンスセンター」>「フレームワーク」** から作成できます。\n\n\n![コンプライアンスフレームワークラベル](https://about.gitlab.com/images/blogimages/compliance-04-2022/cf-step-2.png)\n\n\n**注**：コンプライアンスラベルは、ラベルを作成したトップレベルグループ内のプロジェクトにのみ割り当てられます。\n\n\nポリシーには、[スキャン実行ポリシー](https://docs.gitlab.com/ee/user/application_security/policies/scan_execution_policies.html)、[マージリクエスト承認ポリシー](https://docs.gitlab.com/ee/user/application_security/policies/merge_request_approval_policies.html)、[パイプライン実行ポリシー](https://docs.gitlab.com/ee/user/application_security/policies/pipeline_execution_policies.html)の3種類があります。\n\n\n* **スキャン実行ポリシー**：セキュリティスキャンが、あらかじめ設定したスケジュールに従って実行されるか、プロジェクトのパイプライン内で実行されるようにします。\n\n* **マージリクエスト承認ポリシー**：マージを実行する前にセキュリティチームによる承認を求めるなど、スキャン結果に基づいてアクションを実行します。\n\n* **パイプライン実行ポリシー**：対象のプロジェクトでCI/CDジョブを実施します。\n\n\nこれらのポリシーは、ポリシーエディタ上で簡単な手順で設定できます。\n\n\n### スキャンの実行\n\n\n1. **「セキュリティとコンプライアンス」 >「ポリシー」** の順に移動します。\n\n2. **「新しいポリシー」** ボタンをクリックして新規ポリシーを作成します。\n\n3. **「スキャン実行」** を選択します。\n\n4. ルールを作成します。例として、[SAST](https://docs.gitlab.com/ee/user/application_security/sast/)が設定されていなければパイプラインを実行できないようにするルールを作成します。\n\n\n```yaml\n\nname: force_sast\n\ndescription: 'require sast to run'\n\nenabled: true\n\nrules:\n\n- type: pipeline branches: - main actions:\n\n- scan: sast\n\n```\n\n\n5. マージリクエストを作成してからマージを実行し、ポリシーを送信します。\n\n\nすべてのスキャン実行ポリシーの変更は、10分ごとに実行されるバックグラウンドジョブを通じて適用されます。\n\n対象プロジェクトにコミットされたポリシーの変更が反映されるまで、最長で10分かかることがあります。\n\n\n6. パイプラインを実行してみてください。YAMLでSASTを定義していない場合、パイプラインは実行されません。\n\n\n**注**：タイマーを設定してSASTを強制的に実行することもできます。詳細はスキャン実行ポリシーの\n\n[ドキュメント](https://docs.gitlab.com/ee/user/application_security/policies/scan-execution-policies.html)をご参照ください。\n\n\n### マージリクエストの承認\n\n\n1. **「セキュア」>「ポリシー」** の順に移動します。\n\n2. **「新しいポリシー」** ボタンをクリックして新規ポリシーを作成します。\n\n3. **「マージリクエスト承認ポリシー」** を選択します。\n\n4. ポリシーのスコープを定義します。\n\n5. ルールを作成します。\n\n\n![職務分離のための更新 - 画像1](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098241214.png)\n\n\n6. 実行するアクションを追加します。\n\n\n![職務分離のための更新 - 画像2](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098241215.png)\n\n\n**注**：ポリシーは設定したルールに従って評価されます。 そのため、ルールが無効であるか評価できない場合は、承認が必要となります。これを防ぐには、デフォルトのフォールバック動作フィールドを`open`に変更します。\n\n\n![職務分離のための更新 - 画像3](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750098241217.png)\n\n\n1. マージリクエストを作成してからマージを実行し、ポリシーを送信します。\n\n2. 脆弱性を含むマージリクエストを別途作成します。\n\n\n脆弱性の追加方法については、GitLab DevSecOpsワークショップの「デベロッパーワークフロー」セクションをご参照ください。\n\n\n3. マージリクエストを表示して、マージリクエスト承認ポリシーが使用されていることを確認します。\n\n\n### パイプライン実行ポリシー\n\n\nパイプライン実行ポリシーを設定するには、まず実行するCIファイルを含むプロジェクトを作成する必要があります。職務分離を確実にするため、セキュリティチームや管理者だけがアクセスできるように設定してください。例として、適用したいYAMLを含む「コンプライアンスとデプロイ」プロジェクトを作成しました。\n\n\n1. **「セキュア」>「ポリシー」** の順に移動します。\n\n2. **「新しいポリシー」** ボタンをクリックして新規ポリシーを作成します。\n\n3. **「パイプライン実行ポリシー」** を選択します。\n\n4. ポリシーのスコープを定義します。\n\n5. 実行するアクションを追加します。\n\n\n![職務分離のための更新 - 画像4](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image8_aHR0cHM6_1750098241219.png)\n\n\n6. 条件を追加します。\n\n7. マージリクエストを作成してからマージを実行し、ポリシーを送信します。\n\n8. パイプラインを実行してみてください。パイプラインにポリシー固有のジョブとステージが表示されます。\n\n\n## 監査管理とコンプライアンスダッシュボード\n\n\nコンプライアンスを遵守する上でもうひとつ重要なのは、実際にグループやプロジェクト内で起きていることを把握することです。GitLabには、監査に対応するために監査イベントとコンプライアンスレポートが備わっています。\n\n\n**監査イベント**を使用すると、GitLabのオーナーと管理者は、特定のアクションを実行したユーザーや、そのアクションが行われた時間といった重要なイベントを追跡できます。\n\n\n![監査イベント](https://about.gitlab.com/images/blogimages/compliance-04-2022/project-audit-events.png)\n\n\n監査イベントはグループやプロジェクトごとにさまざまなイベントを記録するもので、[監査イベント](https://docs.gitlab.com/ee/administration/audit_events.html)のドキュメントで内容を\n\n確認できます。\n\n監査イベントには、**「セキュリティとコンプライアンス」>「監査イベント」**の順に移動してアクセスできます。\n\n以下はその一例です。\n\n\n* ユーザーがプロジェクトに追加され、権限が付与された\n\n* プロジェクトに割り当てられたユーザーの権限が変更された\n\n* プロジェクトにCI/CD変数が追加または削除された、または保護された状態が変更された\n\n* ユーザーがグループに追加され、権限が付与された\n\n* グループ名またはパスが変更された\n\n\n監査イベントは、監査イベントストリーミングを使用してHTTPエンドポイントに送信することもできます。監査イベントストリーミングの\n\n実装方法については、こちらの[動画](https://youtu.be/zHwVF9-i7e4?t=52)をご覧ください。\n\n\n**「基準遵守」**では、グループのマージリクエストアクティビティを確認できます。ここでは、グループ内のすべてのプロジェクトの概要が表示されます。\n\n\n![職務分離のための更新 - 画像5](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098241/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750098241222.png)\n\n\nこのレポートでは、次の情報を確認できます。\n\n\n* 各プロジェクトの最新のマージリクエストの概要\n\n* マージリクエストの承認ステータスや承認者\n\n* マージリクエストの作成者\n\n* 各マージリクエストの最新のCI/CDパイプライン結果\n\n\n基準遵守レポートは、トップレベルグループの **「セキュア」 >「コンプライアンスセンター」**にある**「基準遵守」** タブから確認できます。\n\n\n- - -\n\n\nここまでお読みいただきありがとうございました。GitLabでの職務分離について詳しくは、[GitLabによる継続的なソフトウェアコンプライアンス](/solutions/compliance/)をご参照ください。\n",[702,703],"Beatriz Barbosa","Fernando Diaz","2025-07-15","2022-04-04",[680,9],"security",{"slug":709,"featured":6,"template":685},"ensuring-compliance","content:ja-jp:blog:ensuring-compliance.yml","Ensuring Compliance","ja-jp/blog/ensuring-compliance.yml","ja-jp/blog/ensuring-compliance",{"_path":715,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":716,"content":722,"config":731,"_id":733,"_type":14,"title":734,"_source":16,"_file":735,"_stem":736,"_extension":19},"/ja-jp/blog/from-code-to-production-a-guide-to-continuous-deployment-with-gitlab",{"ogTitle":717,"schema":718,"ogImage":719,"ogDescription":720,"ogSiteName":668,"noIndex":6,"ogType":669,"ogUrl":721,"title":717,"canonicalUrls":721,"description":720},"コードから本番環境へ：GitLabを活用した継続的デプロイのガイド","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"コードから本番環境へ：GitLabを活用した継続的デプロイのガイド\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Benjamin Skierlak\"},{\"@type\":\"Person\",\"name\":\"James Wormwell\"}],\n        \"datePublished\": \"2025-01-28\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659478/Blog/Hero%20Images/REFERENCE_-_Use_this_page_as_a_reference_for_thumbnail_sizes.png","GitLabを活用して堅牢な継続的デプロイパイプラインを構築する方法をご紹介します。具体的な手順や例、ベストプラクティスを通して段階的にプロセスを理解できます。","https://about.gitlab.com/blog/from-code-to-production-a-guide-to-continuous-deployment-with-gitlab",{"heroImage":719,"body":723,"authors":724,"updatedDate":727,"date":728,"title":717,"tags":729,"description":720,"category":730},"継続的デプロイは、チームがより迅速かつ高い信頼性で価値を生み出せる画期的な手法です。しかし、GitOpsやKubernetesを用いたコンテナオーケストレーション、動的環境などの高度なデプロイワークフローに取り組むのは、継続的デプロイの導入を始めたばかりのチームにとってはハードルが高いと感じられるかもしれません。\n\n\nGitLabでは、シームレスかつスケーラブルなデリバリーを実現することに注力しています。チームが基本に集中できるようにすることで、時間をかけてより複雑な戦略へと発展できる、強固な基盤を構築できます。このガイドでは、GitLabを活用した継続的デプロイの導入に必要な基本的なステップを紹介し、長期的な成功のための土台作りをサポートします。\n\n\n## まずはワークフローの計画から\n\n\n技術的な実装に入る前に、デプロイワークフローをしっかりと設計する時間を取りましょう。成功の鍵は、慎重な計画と体系的なアプローチにあります。\n\n\n### アーティファクト管理戦略\n\n\n継続的デプロイにおいて、アーティファクトとは、ビルドプロセスによって生成されるパッケージ化された成果物を指し、保存、バージョン管理、デプロイが必要です。アーティファクトには、次のようなものが含まれます。\n\n\n* アプリケーション用のコンテナイメージ\n\n* パッケージ\n\n* コンパイル済みのバイナリや実行ファイル\n\n* ライブラリ\n\n* 設定ファイル\n\n* ドキュメントパッケージ\n\n* その他のアーティファクト\n\n\n各アーティファクトは、デプロイプロセスにおいて特定の役割を果たします。たとえば、一般的なWebアプリケーションでは、次のようなアーティファクトが生成されることがあります。\n\n\n* バックエンドサービス用のコンテナイメージ\n\n* コンパイル済みフロントエンドアセットのZIPアーカイブ\n\n* データベース変更用のSQLファイル\n\n* 環境ごとの設定ファイル\n\n\nアーティファクトの適切な管理はデプロイを成功させる鍵となります。ここからは、アーティファクト管理のアプローチについて詳しく見ていきましょう。\n\n\n#### アーティファクトとリリースのバージョニング戦略\n\n\nクリーンで整理された構造を保つためのベストプラクティスとして、アーティファクトの明確なバージョニング戦略を確立することが重要です。リリース作成時のポイントは以下のとおりです。\n\n\n* リリースタグにセマンティックバージョニング（major.minor.patch）を使用する\n\n  * 例：安定版リリースが`myapp:1.2.3`の場合\n  * 破壊的な変更がある場合は、メジャーバージョン変更（2.0.0）\n  * 新機能を追加する場合は、マイナーバージョン変更（1.3.0）\n  * バグ修正を行う場合は、パッチバージョン変更（1.2.4）\n* 最新の安定版を示す「latest」タグを維持する\n\n  * 例：`myapp:latest`（自動デプロイ用）\n* コミットSHAを含めることで、正確なバージョン追跡を行う\n\n  * 例：`myapp:1.2.3-abc123f`（デバッグ用）\n* 開発環境向けにブランチベースのタグを使用する\n\n  * 例：`myapp:feature-user-auth`（新機能テスト用）\n\n#### ビルドアーティファクトの保持\n\n\n明確な保持ルールを実装しましょう。\n\n\n* 一時的なアーティファクトの明確な有効期限を設定する\n\n* 永続的に保持する必要があるアーティファクトを定義する\n\n* ストレージ管理のためのクリーンアップポリシーを設定する\n\n\n#### レジストリアクセスと認証\n\n\n適切なアクセス制御でアーティファクトのセキュリティを確保しましょう。\n\n\n* デベロッパーのアクセス用にパーソナルアクセストークンを実装する\n\n* パイプラインの認証にCI/CD変数を設定する\n\n* 適切なアクセススコープを設定する\n\n\n### 環境戦略\n\n\n環境設計はデプロイパイプライン全体の構成に影響を与えるため、早い段階で検討しましょう。\n\n\n* 開発、ステージング環境、本番環境の設定\n\n* 環境ごとの変数とシークレットの管理\n\n* アクセス制御と保護ルールの設定\n\n* デプロイの追跡とモニタリングのアプローチ\n\n\n### デプロイターゲット\n\n\nどこに、どのようにデプロイするのかを慎重に検討しましょう。これらの決定は重要であり、それぞれのメリットとデメリットを考慮する必要があります。\n\n\n* インフラ要件（仮想マシン、コンテナ、クラウドサービス）\n\n* ネットワークアクセスとセキュリティ設定\n\n* 認証メカニズム（SSH鍵、アクセストークン）\n\n* リソースの割り当てとスケーリングの考慮\n\n\nこれで戦略が定まり、基盤となる決定が完了したので、これらの計画を実際に動作するパイプラインに落とし込んでいきます。それでは、実際に機能する例を作ることで概念を深掘りしていきましょう。まずはシンプルなアプリケーションから始め、徐々にデプロイの機能を追加していきます。\n\n\n## CDパイプラインの実装\n\n\n### 具体的な手順\n\n\nWebアプリケーション向けの基本的な継続的デプロイ（CD）パイプラインの実装手順を順を追って説明します。例としてシンプルなHTMLアプリケーションを使用しますが、ここで紹介する原則はどのタイプのアプリケーションにも応用できます。今回は、アプリケーションをDockerイメージとしてパッケージ化し、シンプルな仮想マシン上にデプロイします。これにより、最小限の依存関係を持つ厳選されたイメージを活用し、環境依存の要件が意図せず混入するのを防ぐことができます。また、仮想マシン上で動作させることで、GitLabのネイティブなインテグレーション機能を活用しない設定となります。複雑で本格的な環境ではなく、理解しやすい簡易的な環境から始めてみましょう。\n\n\n#### 前提条件\n\n\nこの例では、クラウドプロバイダーの仮想マシン上で実行するアプリケーションをコンテナ化することを目指します。また、ローカル環境でもこのアプリケーションをテストします。以下の前提条件は、このシナリオにおいてのみ必要なものです。\n\n\n##### [仮想マシン（VM）](https://about.gitlab.com/ja-jp/blog/what-is-vm/)のセットアップ\n\n\n* お好みのクラウドプロバイダーで[VM](https://about.gitlab.com/ja-jp/blog/what-is-vm/)をプロビジョニングします（例：GCP、AWS、Azure）\n\n* ネットワークルールを設定し、ポート22、80、443へのアクセスを許可します\n\n* デプロイ用にマシンのパブリックIPアドレスを記録します\n\n\n##### SSH認証のセットアップ：\n\n\n* マシン用の公開鍵と秘密鍵のペアを生成します\n\n* GitLabで**設定 > CI/CD > 変数**を開きます\n\n* `GITLAB_KEY`という変数を作成します\n\n* タイプを「ファイル」に設定します（SSH認証に必須）\n\n* 秘密鍵を「値」フィールドに貼り付けます\n\n* 「ユーザー」変数を定義します（VMにログインしてスクリプトを実行するユーザー）\n\n\n##### デプロイ変数の設定\n\n\n* デプロイターゲット用の変数を作成します\n\n  * `STAGING_TARGET`：ステージング環境のサーバーIPまたはドメイン\n  * `PRODUCTION_TARGET`：本番環境のサーバーIPまたはドメイン\n\n##### ローカル開発環境のセットアップ\n\n\n* デプロイのテスト用に、ローカルマシンにDockerをインストールします\n\n\n##### GitLabコンテナレジストリへのアクセス\n\n\n* レジストリパスを確認します：\n\n  * **デプロイ > コンテナレジストリ**を開きます\n  * レジストリパスをコピーします（例：registry.gitlab.com/group/project）\n* 認証の設定：\n\n  * **設定 > アクセストークン**を開きます\n  * レジストリアクセス権を持つ新しいトークンを作成します\n  * トークンの有効期限を最大1年に設定します\n  * トークンを安全に保存します\n* ローカルレジストリのアクセス設定：\n\n\n```\n\ndocker login registry.gitlab.com\n\n\n# パーソナルアクセストークンを使用する場合のユーザー名はgitlab-ci-tokenです\n\n\n# Password:（ここにアクセストークンを入力）\n\n```\n\n\n#### 1. アプリケーションを作成する\n\n\n基本的なWebアプリケーションから始めましょう。今回の例では、シンプルなHTMLページを使用します。\n\n\n```\n\n\u003C!|||UNTRANSLATED_CONTENT_START|||-- index.html -->\n\n\n\u003Chtml>\n  \u003Chead>\n    \u003Cstyle>\n      body {\n        background-color: #171321; /* GitLab dark */\n      }\n    \u003C/style>\n  \u003C/head>\n  \u003Cbody>\n    \u003C!|||UNTRANSLATED_CONTENT_END|||-- ここにコンテンツを追加 -->\n  \u003C/body>\n\u003C/html>\n\n```\n\n\n#### 2. アプリケーションをコンテナ化する\n\n\nアプリケーションをパッケージ化するために、Dockerfileを作成します：\n\n\n```\n\nFROM nginx:1.26.2\n\n\nCOPY index.html /usr/share/nginx/html/index.html\n\n```\n\n\nこのDockerfileは\n\n\n* nginxをベースイメージとして使用し、Webコンテンツを配信できるようにします\n\n* 作成したindex.htmlをnginxのディレクトリ構造内の適切な場所にコピーします\n\n\n#### 3. CI/CDパイプラインを設定する\n\n\nGitLabのパイプラインステージを定義するために、`.gitlab-ci.yml`ファイル を作成します：\n\n\n```\n\nvariables:\n  TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest\n  TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHA\n\nstages:\n  - publish\n  - deploy\n```\n\n\n解説：\n\n\n`TAG_LATEST`は、次の3つの要素で構成されています：\n\n\n* `$CI_REGISTRY_IMAGE`：GitLabのプロジェクトのコンテナレジストリのパス\n\n\n例：`registry.gitlab.com/your-group/your-project`\n\n\n* `$CI_COMMIT_REF_NAME`：ブランチ名またはタグ名\n\n\n例：ブランチの場合は`/main`、フィーチャーブランチの場合は`/feature-login`\n\n\n* `:latest`：固定のサフィックス\n\n\nこれにより、mainブランチの`TAG_LATEST`は次のようになります：`registry.gitlab.com/your-group/your-project/main:latest`\n\n\n`TAG_COMMIT`は`TAG_LATEST`とほぼ同じですが、`:latest`の代わりにコミット識別子の`$CI_COMMIT_SHA`を使います。例：`:abc123def456`\n\n\nしたがって、同じmainブランチでの`TAG_COMMIT`は次のようになります：`registry.gitlab.com/your-group/your-project/main:abc123def456`\n\n\n両方のタグを使用する理由は、`TAG_LATEST`が常に最新バージョンを取得しやすくするのに対し、`TAG_COMMIT`は必要に応じて特定のバージョンに戻れるようにするためです。\n\n\n#### 4. コンテナレジストリに公開する\n\n\nパイプラインに公開ジョブを追加します：\n\n\n```\n\npublish:\n  stage: publish\n  image: docker:latest\n  services:\n    - docker:dind\n  script:\n    - docker build -t $TAG_LATEST -t $TAG_COMMIT .\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker push $TAG_LATEST\n    - docker push $TAG_COMMIT\n```\n\n\nこのジョブは\n\n\n* Docker-in-Dockerを使用してイメージをビルドします\n\n* 2つのタグを付けたイメージを作成します\n\n* GitLabレジストリへの認証を行います\n\n* 両方のイメージをレジストリにプッシュします \n\n\nこれで、コンテナイメージが安全にレジストリに保存されました。次は、ターゲット環境へのデプロイを進めていきます。本番環境へ移行する前に、まずローカル環境でテストを行い、設定が正しく機能していることを確認しましょう。 \n\n\n#### 5. 環境へデプロイする\n\n\n本番環境にデプロイする前に、ローカル環境でテストできます。先ほどGitLabレジストリにイメージを公開したので、それをローカル環境でプルしてテストします。コンテナイメージのパスが分からない場合は、GitLabの\\*\\*デプロイ\n\n\n> コンテナレジストリ\\*\\*に移動し、該当のコンテナイメージの行末にあるアイコンをクリックすると、パスをコピーできます。\n\n\n```\n\ndocker login registry.gitlab.com \n\n\ndocker run -p 80:80 registry.gitlab.com/your-project-path/main:latest\n\n```\n\n\nこれにより、Webブラウザからlocalhostにアクセスし、ローカル環境でアプリケーションを確認できるようになります。\n\n\nそれでは、パイプラインにデプロイジョブを追加しましょう：\n\n\n```\n\ndeploy:\n  stage: deploy\n  image: alpine:latest\n  script:\n    - chmod 400 $GITLAB_KEY\n    - apk add openssh-client\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$TARGET_SERVER \n      docker pull $TAG_COMMIT &&\n      docker rm -f myapp || true &&\n      docker run -d -p 80:80 --name myapp $TAG_COMMIT\n```\n\n\nこのジョブは\n\n\n* デプロイ先のサーバーへのSSHアクセスを確立します\n\n* 最新のコンテナイメージをプルします\n\n* 既存のコンテナを削除します\n\n* 新しいバージョンのコンテナをデプロイします\n\n\n#### 6. デプロイを追跡する\n\n\n環境設定を追加してデプロイの追跡を有効にします：\n\n\n```\n\ndeploy:\n  environment:\n    name: production\n    url: https://your-application-url.com \n```\n\n\nこれにより、GitLabの**オペレーション > 環境**セクションに環境オブジェクトが作成され、以下の情報が提供されます：\n\n\n* デプロイ履歴\n\n* 現在のデプロイ状況\n\n* アプリケーションへのクイックアクセス\n\n\n単一の環境向けのパイプラインは、最初のステップとしては有効ですが、ほとんどのチームでは適切なテストやステージングを行うために複数の環境を管理する必要があります。このより実践的なシナリオに対応するために、パイプラインを拡張していきましょう。\n\n\n#### 7. 複数環境をセットアップする\n\n\nより堅牢なパイプラインを構築するために、ステージング環境と本番環境のデプロイを設定します：\n\n\n```\n\nstages:\n  - publish\n  - staging\n  - release\n  - version\n  - production\n\nstaging:\n  stage: staging\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\" && $CI_COMMIT_TAG == null\n  environment:\n    name: staging\n    url: https://staging.your-app.com\n  # デプロイスクリプトを記述\n\nproduction:\n  stage: production\n  rules:\n    - if: $CI_COMMIT_TAG\n  environment:\n    name: production\n    url: https://your-app.com\n  # デプロイスクリプトを記述\n```\n\n\nこの設定は\n\n\n* mainブランチからステージ環境へデプロイします\n\n* GitLabのタグを利用して本番環境へのデプロイをトリガーします\n\n* 環境ごとに分けてデプロイの状況を管理できるようにします\n\n\nこのステップと次のステップでは、GitLabの非常に便利な機能であるタグを活用しています。GitLabの**コード >\n\nタグ**セクションで手動でタグを作成すると、'$ CI_COMMMIT_TAG\n\n`変数が設定され、本番環境へのデプロイジョブが適切にトリガーされるようになります。\n\n\n#### 8. 自動リリースノートを作成する\n\n\nCI/CDパイプラインを通じてGitLabのリリース機能を使用します。まず、`.gitlab-ci.yml`のstagesを更新 します：\n\n\n```\n\nstages:\n\n\n\n- publish\n\n\n- staging\n\n\n- release # New stage for releases\n\n\n- version\n\n\n- production\n\n```\n\n\n次に、リリースジョブを追加します：\n\n\n```\n\nrelease_job:\n  stage: release\n  image: registry.gitlab.com/gitlab-org/release-cli:latest\n  rules:\n    - if: $CI_COMMIT_TAG                  # タグが作成された場合のみ実行する\n  script:\n    - echo \"Creating release for $CI_COMMIT_TAG\"\n  release:                                # リリース設定\n    name: 'Release $CI_COMMIT_TAG'\n    description: 'Release created from $CI_COMMIT_TAG'\n    tag_name: '$CI_COMMIT_TAG'           # タグを作成する\n    ref: '$CI_COMMIT_TAG'                # リリースのベースとなるタグ\n```\n\n\nコンテナイメージのリンクを追加することで、さらに内容を充実させることができます：\n\n\n```\n\nrelease:\n  name: 'Release $CI_COMMIT_TAG'\n  description: 'Release created from $CI_COMMIT_TAG'\n  tag_name: '$CI_COMMIT_TAG'\n  ref: '$CI_COMMIT_TAG'\n  assets:\n    links:\n      - name: 'Container Image'\n        url: '$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG'\n        link_type: 'image'\n```\n\n\nコミットメッセージに基づいて自動リリースノートを生成する場合は次のようにします：\n\n\n```\n\nrelease:\n  name: 'Release $CI_COMMIT_TAG'\n  description: 'Release notes for version $CI_COMMIT_TAG'\n  tag_name: '$CI_COMMIT_TAG'\n  ref: '$CI_COMMIT_TAG'\n  auto_generate_release_notes: true    # Enables automatic notes\n```\n\n\n自動リリースノートを充実させるには\n\n\n* 規則的なコミットメッセージを使用する（例：feat:, fix:）\n\n* イシュー番号を含める（例：#123）\n\n* 件名と本文の間に空行を入れる\n\n\nデプロイ時の情報をリリースノートに記載したい場合は、以下のように設定できます：\n\n\n```\n\nrelease_job:\n  script:\n    - |\n      DEPLOY_TIME=$(date '+%Y-%m-%d %H:%M:%S')\n      CHANGES=$(git log $(git describe --tags --abbrev=0 @^)..@ --pretty=format:\"- %s\")\n      cat > release_notes.md \u003C\u003C EOF\n      ## デプロイ情報\n      - デプロイ日時: $DEPLOY_TIME\n      - 環境: 本番環境\n      - バージョン: $CI_COMMIT_TAG\n\n      ## 変更内容\n      $CHANGES\n\n      ## アーティファクト\n      - コンテナイメージ: \\`$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\\`\n      EOF\n  release:\n    description: './release_notes.md'\n```\n\n\nこの設定を行うと、Gitタグの作成時に自動でリリースが作成されるようになります。作成されたリリースは、GitLabの**デプロイ >\n\nリリース**で確認できます。\n\n\n#### 9. すべてをまとめる\n\n\n最終的なYAMLファイルは以下のようになります：\n\n\n```\n\nvariables:\n  TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest\n  TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHA\n  STAGING_TARGET: $STAGING_TARGET    # CI/CD変数で設定\n  PRODUCTION_TARGET: $PRODUCTION_TARGET  # CI/CD変数で設定\n\nstages:\n  - publish\n  - staging\n  - release\n  - version\n  - production\n\n# ビルドとレジストリへの公開\n\n\npublish:\n  stage: publish\n  image: docker:latest\n  services:\n    - docker:dind\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\" && $CI_COMMIT_TAG == null\n  script:\n    - docker build -t $TAG_LATEST -t $TAG_COMMIT .\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker push $TAG_LATEST\n    - docker push $TAG_COMMIT\n\n# stagingへデプロイ\n\n\nstaging:\n  stage: staging\n  image: alpine:latest\n  rules:\n    - if: $CI_COMMIT_BRANCH == \"main\" && $CI_COMMIT_TAG == null\n  script:\n    - chmod 400 $GITLAB_KEY\n    - apk add openssh-client\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$STAGING_TARGET \"\n        docker pull $TAG_COMMIT &&\n        docker rm -f myapp || true &&\n        docker run -d -p 80:80 --name myapp $TAG_COMMIT\"\n  environment:\n    name: staging\n    url: http://$STAGING_TARGET\n\n# リリースの作成\n\n\nrelease_job:\n  stage: release\n  image: registry.gitlab.com/gitlab-org/release-cli:latest\n  rules:\n    - if: $CI_COMMIT_TAG\n  script:\n    - |\n      DEPLOY_TIME=$(date '+%Y-%m-%d %H:%M:%S')\n      CHANGES=$(git log $(git describe --tags --abbrev=0 @^)..@ --pretty=format:\"- %s\")\n      cat > release_notes.md \u003C\u003C EOF\n      ## デプロイ情報\n      - デプロイ日時：$DEPLOY_TIME\n      - 環境：本番環境\n      - バージョン：$CI_COMMIT_TAG\n\n      ## 変更内容\n      $CHANGES\n\n      ## アーティファクト\n      - コンテナイメージ：\\`$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\\`\n      EOF\n  release:\n    name: 'Release $CI_COMMIT_TAG'\n    description: './release_notes.md'\n    tag_name: '$CI_COMMIT_TAG'\n    ref: '$CI_COMMIT_TAG'\n    assets:\n      links:\n        - name: 'コンテナイメージ'\n          url: '$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG'\n          link_type: 'image'\n\n# リリースタグ付きのバージョンを作成\n\n\nversion_job:\n  stage: version\n  image: docker:latest\n  services:\n    - docker:dind\n  rules:\n    - if: $CI_COMMIT_TAG\n  script:\n    - docker pull $TAG_COMMIT\n    - docker tag $TAG_COMMIT $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker push $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\n\n# 本番環境へデプロイ\n\n\nproduction:\n  stage: production\n  image: alpine:latest\n  rules:\n    - if: $CI_COMMIT_TAG\n  script:\n    - chmod 400 $GITLAB_KEY\n    - apk add openssh-client\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$PRODUCTION_TARGET \"\n        docker pull $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG &&\n        docker rm -f myapp || true &&\n        docker run -d -p 80:80 --name myapp $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\"\n  environment:\n    name: production\n    url: http://$PRODUCTION_TARGET\n```\n\n\n完成したパイプラインは\n\n\n* mainブランチでの変更をレジストリに公開します\n\n* mainブランチでの変更をstagingへデプロイします\n\n* タグが作成された際にリリースを作成します\n\n* リリースタグを付けたイメージを作成します\n\n* タグを基に本番環境へデプロイします\n\n\n主なメリット：\n\n\n* クリーンで再現性のあるローカル開発およびテスト環境が完成します\n\n* 構造化された本番環境へのデプロイフローにより、信頼性の高いデプロイを実現できます\n\n* 予期しない障害からの復旧パターンを確立します\n\n* より複雑なデプロイ戦略への拡張/導入に対応できます\n\n*\n\n\n### ベストプラクティス\n\n\n実装の際は、以下の原則を守りましょう：\n\n\n* 変数の使用方法からデプロイ手順まで、すべてを文書化する\n\n* GitLabのビルトイン機能（環境管理、リリース、レジストリ）を活用する\n\n* 適切なアクセス制御とセキュリティ対策を実施する\n\n* 強固なロールバック手順を計画し、障害に備える\n\n* パイプラインの設定はDRY（Don't Repeat Yourself：重複を避ける）を意識する\n\n\n## デプロイ戦略をスケールさせる\n\n\n次は何をすべきでしょうか？ここでは、継続的デプロイ戦略をさらに成熟させるために、検討すべきポイントを紹介します。\n\n\n### 高度なセキュリティ対策\n\n\n以下の方法でセキュリティを強化しましょう：\n\n\n* アクセスを制限した保護環境を設定する\n\n* 本番環境へのデプロイに承認を必須とする\n\n* セキュリティスキャンをパイプラインに統合する\n\n* 自動脆弱性評価を導入する\n\n* デプロイ関連の変更に対するブランチ保護ルールを適用する\n\n\n### 段階的なデリバリー戦略\n\n\n以下のような高度なデプロイ戦略を実装しましょう。\n\n\n* 機能フラグを活用して制御されたロールアウトを行う\n\n* リスクを軽減するためにカナリアデプロイを実施する\n\n* ブルーグリーンデプロイ戦略を導入する\n\n* A/Bテストを実施する\n\n* 動的環境管理を行う\n\n\n### モニタリングと最適化\n\n\n強固なモニタリング体制を確立しましょう：\n\n\n* デプロイ指標を追跡する\n\n* パフォーマンスモニタリングをセットアップする\n\n* デプロイアラートを設定する\n\n* デプロイのサービスレベル目標（SLO）を確立する\n\n* 定期的にパイプラインを最適化する\n\n\n## GitLabが選ばれる理由\n\n\nGitLabの継続的デプロイ機能は、現代のデプロイワークフローに最適です。GitLabは、コンテナレジストリ、環境管理、デプロイ追跡などの機能が1つのインターフェースに集約されており、コードから本番環境へのプロセスを効率化します。また、環境ごとの変数、デプロイ承認ゲート、ロールバック機能を備えており、本番環境へのデプロイ時に求められるセキュリティと管理を実現します。さらに、Review\n\nApps（レビューアプリ）や機能フラグを活用することで、段階的なデリバリー（プログレッシブデリバリー）戦略も可能です。GitLabのDevSecOpsプラットフォームの一部として、これらのCD機能はソフトウェアライフサイクル全体とシームレスに連携します。\n\n\n## 無料トライアルで今すぐスタート！\n\n\n継続的デプロイへの道のりは、革命ではなく進化のプロセスです。まずは基本を押さえ、しっかりとした基盤を築き、チームの成長に応じて徐々に高度な機能を取り入れていきましょう。GitLabは、最初の自動デプロイから、複数環境にまたがる複雑なデリバリーパイプラインまで、あらゆる段階でサポートするためのツールと柔軟性を提供します。 \n\n\n> [GitLab\n\n> Ultimateの無料トライアル](https://about.gitlab.com/ja-jp/free-trial/devsecops/)で、今日から継続的デプロイメントを始めましょう。\n\n\n\u003Cbr>\u003Cbr>\n\n\n\\*監修：川瀬 洋平 [@ykawase](https://gitlab.com/ykawase)\u003Cbr>\n\n\n（GitLab合同会社 カスタマーサクセス本部 シニアカスタマーサクセスマネージャー）*\n",[725,726],"Benjamin Skierlak","James Wormwell","2025-06-11","2025-01-28",[9,109,678,730,681],"product",{"slug":732,"featured":6,"template":685},"from-code-to-production-a-guide-to-continuous-deployment-with-gitlab","content:ja-jp:blog:from-code-to-production-a-guide-to-continuous-deployment-with-gitlab.yml","From Code To Production A Guide To Continuous Deployment With Gitlab","ja-jp/blog/from-code-to-production-a-guide-to-continuous-deployment-with-gitlab.yml","ja-jp/blog/from-code-to-production-a-guide-to-continuous-deployment-with-gitlab",{"_path":738,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":739,"content":745,"config":752,"_id":754,"_type":14,"title":755,"_source":16,"_file":756,"_stem":757,"_extension":19},"/ja-jp/blog/getting-started-with-gitlab-understanding-ci-cd",{"title":740,"description":741,"ogTitle":740,"ogDescription":741,"noIndex":6,"ogImage":742,"ogUrl":743,"ogSiteName":668,"ogType":669,"canonicalUrls":743,"schema":744},"GitLab入門：CI/CDについて理解する","この初心者向けガイドでは、継続的インテグレーション（CI）／継続的デリバリー（CD）の基本（CI/CDコンポーネントの概要や作成方法など）を解説します。","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659525/Blog/Hero%20Images/blog-getting-started-with-gitlab-banner-0497-option4-fy25.png","https://about.gitlab.com/blog/getting-started-with-gitlab-understanding-ci-cd","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab入門：CI/CDについて理解する\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab\"}],\n        \"datePublished\": \"2025-04-25\",\n      }",{"title":740,"description":741,"authors":746,"heroImage":742,"date":748,"body":749,"category":730,"tags":750},[747],"GitLab","2025-04-25","すべてのコード変更が自動的にビルドおよびテストされ、そのうえでユーザーにデプロイされる。そんなワークフローを想像してみてください。それを可能にするのが、[継続的インテグレーション／継続的デリバリー（CI/CD）](https://about.gitlab.com/ja-jp/topics/ci-cd/)です。CI/CDは、バグの早期発見、コード品質の確保、および迅速かつ頻繁なソフトウェアデリバリーの実現に役立ちます。\n\n\n### CI/CDとは\n\n\n*\n**継続的インテグレーション（CI）**は、デベロッパーがコード変更を頻繁に（1日に数回が理想とされる）共有リポジトリに統合する開発手法です。各統合は自動化されたビルドとテストのプロセスによって検証されるため、早い段階で問題を検出できます。\n\n*\n**継続的デリバリー（CD）**はCIを拡張した開発手法で、リリースパイプラインを自動化することで、コードを*常に*デプロイ可能な状態に保ちます。アプリケーションをさまざまな環境（stagingステージ、本番環境など）に自動的に、またはワンクリックでデプロイできます。\n\n*\n**継続的デプロイ**はさらにもう一歩踏み込み、本番環境に*成功したビルドをすべて*デプロイする手法です。継続的デプロイは、自動化されたテストとデプロイのプロセスに十分な信頼性がある場合にのみ、有効です。\n\n\n### GitLab CI/CDが選ばれる理由\n\n\nGitLab\nCI/CDは、GitLabに組み込まれた強力な統合システムです。これを利用することで、ソフトウェア開発ライフサイクル全体をシームレスに自動化できます。GitLab\nCI/CDによって、以下のことを実現できます。\n\n\n* **あらゆるプロセスの自動化**：アプリケーションのビルド、テスト、デプロイを簡単に行えます。\n\n* **バグの早期発見**：問題が本番環境に到達する前に検出し、修正できます。\n\n* **フィードバックループの高速化**：コード変更に関するフィードバックを即座に受け取れます。\n\n* **コラボレーションの向上**：自動化されたワークフローによって、より効果的に共同作業を行えます。\n\n* **デリバリーの高速化**：ソフトウェアをより迅速かつ頻繁にリリースできます。\n\n* **リスクの低減**：デプロイ時のエラーやロールバックを最小限に抑えられます。\n\n\n### GitLab CI/CDの構成要素\n\n\n*\n`.gitlab-ci.yml`：プロジェクトのルートディレクトリにある[YAMLファイル](https://docs.gitlab.com/ee/ci/yaml/)です。ステージやジョブ、Runnerなど、CI/CDパイプラインの構成を定義します。\n\n* [**GitLab\nRunner**](https://docs.gitlab.com/runner/)：任意のインフラストラクチャ（物理マシン、仮想マシン、Dockerコンテナ、Kubernetesクラスターなど）上でCI/CDジョブを実行するエージェントです。\n\n*\n[**ステージ**](https://docs.gitlab.com/ee/ci/yaml/#stages)：ジョブ（ビルド、テスト、デプロイなど）の実行順序を定義します。\n\n*\n[**ジョブ**](https://docs.gitlab.com/ee/ci/yaml/#job-keywords)：ステージ内の個々の作業単位（コードのコンパイル、テストの実行、stagingステージへのデプロイなど）を指します。\n\n\n### GitLab CIの設定\n\n\nGitLab CIは簡単に使い始められます。以下は`.gitlab-ci.yml`ファイルの基本的な設定例です。\n\n\n```yaml\n\n\nstages:\n  - build\n  - test\n  - deploy\n\nbuild_job:\n  stage: build\n  script:\n    - echo \"アプリケーションをビルド中...\"\n\ntest_job:\n  stage: test\n  script:\n    - echo \"テストを実行中...\"\n\ndeploy_job:\n  stage: deploy\n  script:\n    - echo \"本番環境へデプロイ中...\"\n  environment:\n    name: production\n\n```\n\n\nこの設定では、「build」「test」「deploy」の3つのステージを定義しています。それぞれのステージには、単純なスクリプトを実行するジョブが含まれています。\n\n\n### CI/CDの設定例\n\n\n次に、より実践的な例をいくつか見てみましょう。\n\n\n**Node.jsアプリケーションのビルドとデプロイ**\n\n\n以下のパイプライン定義では、npmを使用してNode.jsアプリケーションのビルドおよびテストを行い、[dpl](https://docs.gitlab.com/ci/examples/deployment/)を用いてアプリケーションをHerokuにデプロイする方法を説明しています。パイプラインのdeployステージでは、[GitLab\nCI/CD変数](https://docs.gitlab.com/ci/variables/)を使用しています。デベロッパーは機密情報（認証情報など）をこの変数に格納して、CI/CDプロセスで安全に使用できます。この例では、Herokuにデプロイする際にdplツールが使用するAPIキーが、`$HEROKU_API_KEY`という名前の変数キーに格納されます。\n\n\n```yaml\n\n\nstages:\n  - build\n  - test\n  - deploy\n\nbuild:\n  stage: build\n  image: node:latest\n  script:\n    - npm install\n    - npm run build\n\ntest:\n  stage: test\n  image: node:latest\n  script:\n    - npm run test\n\ndeploy:\n  stage: deploy\n  image: ruby:latest\n  script:\n    - gem install dpl\n    - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_API_KEY\n\n```\n\n\n**異なる環境へのデプロイ（stagingステージや本番環境）**\n\n\nGitLabではさらに、CI/CDを使用した[環境](https://docs.gitlab.com/ci/environments/)という機能もご用意しています。この機能を使用すると、CI/CDから対象のインフラストラクチャへのデプロイを追跡できます。以下の例では、パイプラインにおいてstagingステージと本番環境の環境プロパティを持つステージが追加されます。deploy_stagingステージでは必ず指定したスクリプトが実行される一方、deploy_productionステージでは手動による承認が必要となります。これは誤って本番環境へのデプロイが行われるのを防ぐためです。\n\n\n```yaml\n\n\nstages:\n  - build\n  - test\n  - deploy_staging\n  - deploy_production\n\nbuild:\n  # ...\n\ntest:\n  # ...\n\ndeploy_staging:\n  stage: deploy_staging\n  script:\n    - echo \"stagingステージへのデプロイ中...\"\n  environment:\n    name: staging\n\ndeploy_production:\n  stage: deploy_production\n  script:\n    - echo \"本番環境へのデプロイ中...\"\n  environment:\n    name: production\n  when: manual  # 手動による承認が必要\n\n```\n\n\n### GitLab Auto DevOps\n\n\n[GitLab Auto\nDevOps](https://docs.gitlab.com/ee/topics/autodevops/)は、アプリケーションを自動的にビルド、テスト、デプロイするためのあらかじめ定義された設定を提供することで、CI/CDを簡素化します。ベストプラクティスと業界標準に基づいてワークフローを効率化する仕組みです。\n\n\nAuto DevOpsを有効にする方法：\n\n\n1. プロジェクトの**設定 > CI/CD > 一般パイプライン**の順にアクセスします。\n\n2. **Auto DevOps**オプションを有効にします。\n\n\nAuto\nDevOpsを有効にすると、プロジェクトの言語とフレームワークが自動的に検出され、必要なビルド、テスト、デプロイのステージが設定されます。そのため、`.gitlab-ci.yml`ファイルを作成する必要すらありません。\n\n\n### CI/CDカタログ\n\n\n[CI/CDカタログ](https://about.gitlab.com/blog/faq-gitlab-ci-cd-catalog/)には、CI/CDワークフローを拡張するために使用可能な、公開済みの[CI/CDコンポーネント](https://docs.gitlab.com/ee/ci/components/)をまとめたプロジェクトが一覧で記載されています。誰でもコンポーネント用のプロジェクトを作成してCI/CDカタログに追加したり、既存プロジェクトへのコントリビュートを通じて公開コンポーネントを改善したりできます。これらのコンポーネントは、GitLab.comの[CI/CDカタログ](https://gitlab.com/explore/catalog)に掲載されています。\n\n\n> [チュートリアル：初めてのGitLab\nCI/CDコンポーネントの設定方法](https://about.gitlab.com/blog/tutorial-how-to-set-up-your-first-gitlab-ci-cd-component/)\n\n\n### CIテンプレート\n\n\nさらに、独自の[CIテンプレート](https://docs.gitlab.com/ee/ci/examples/)を作成して、複数のプロジェクトに対するCI/CDの設定を標準化し、再利用することもできます。これにより、一貫性が高まり、重複が生じにくくなります。\n\n\nCIテンプレートの作成方法：\n\n\n1. 専用のプロジェクトまたはリポジトリに`.gitlab-ci.yml`ファイルを作成します。\n\n2. テンプレートでCI/CD設定を定義します。\n\n3. プロジェクトの`.gitlab-ci.yml`ファイルで、`include`キーワードを使用してテンプレートをインクルードします。\n\n\n## 開発ワークフローをレベルアップ\n\n\nGitLab CI/CDは、開発ワークフローに変革をもたらせる強力なツールです。CI/CDの概念を理解して、パイプラインを設定し、Auto\nDevOpsやCI/CDカタログ、CIテンプレートなどの機能を活用すれば、ソフトウェア開発ライフサイクル全体を自動化し、高品質なソフトウェアをより迅速かつ効率的に提供できます。\n\n\n> さらに詳しく知りたい場合は、[GitLab\nUniversityのコースに登録](https://university.gitlab.com/)するか、[GitLab\nUltimateの無料トライアル](https://about.gitlab.com/ja-jp/free-trial/)を今すぐお試しください。\n\n\n## 「GitLab入門」シリーズ\n\n\n「GitLab入門」シリーズのその他の記事もぜひご覧ください。\n\n\n-\n[ユーザーの管理方法](https://about.gitlab.com/ja-jp/blog/getting-started-with-gitlab-how-to-manage-users/)\n\n- \n[GitLabへのプロジェクトのインポート方法](https://about.gitlab.com/blog/getting-started-with-gitlab-how-to-import-your-projects-to-gitlab/)  \n\n-\n[プロジェクト管理を極める](https://about.gitlab.com/blog/getting-started-with-gitlab-mastering-project-management/)\n\n- [gitlab-triage\ngemを使ったアジャイルワークフローの自動化](https://about.gitlab.com/blog/automating-agile-workflows-with-the-gitlab-triage-gem/)\n",[109,680,9,751,730,681],"DevSecOps platform",{"slug":753,"featured":91,"template":685},"getting-started-with-gitlab-understanding-ci-cd","content:ja-jp:blog:getting-started-with-gitlab-understanding-ci-cd.yml","Getting Started With Gitlab Understanding Ci Cd","ja-jp/blog/getting-started-with-gitlab-understanding-ci-cd.yml","ja-jp/blog/getting-started-with-gitlab-understanding-ci-cd",{"_path":759,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":760,"content":765,"config":771,"_id":773,"_type":14,"title":774,"_source":16,"_file":775,"_stem":776,"_extension":19},"/ja-jp/blog/getting-started-with-gitlab-working-with-ci-cd-variables",{"title":761,"description":762,"ogTitle":761,"ogDescription":762,"noIndex":6,"ogImage":742,"ogUrl":763,"ogSiteName":668,"ogType":669,"canonicalUrls":763,"schema":764},"GitLab入門：CI/CD変数を使用する","CI/CD変数の概要、DevSecOpsにおいてCI/CD変数が重要な理由、活用するためのベストプラクティスについてご紹介します。","https://about.gitlab.com/blog/getting-started-with-gitlab-working-with-ci-cd-variables","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab入門：CI/CD変数を使用する\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab Team\"}],\n        \"datePublished\": \"2025-05-27\",\n      }",{"title":761,"description":762,"authors":766,"heroImage":742,"date":768,"body":769,"category":730,"tags":770},[767],"GitLab Team","2025-05-27","*「GitLab入門」シリーズへようこそ。このシリーズでは新たにGitLabを使い始める方向けに、GitLab\nDevSecOpsプラットフォームに慣れ親しむために役立つ内容をお届けします。*\n\n\n以前の記事で、[GitLab\nCI/CD](https://about.gitlab.com/blog/getting-started-with-gitlab-understanding-ci-cd/)について取り上げました。今回は**CI/CD変数**の世界をさらに深く掘り下げ、その力を最大限に引き出す方法について説明します。\n\n\n### CI/CD変数とは\n\n\nCI/CD変数とは、GitLab環境内においてさまざまなレベル（プロジェクト、グループ、インスタンスなど）で定義できる動的なキーと値のペアのことです。`.gitlab-ci.yml`ファイルで使用できる値のプレースホルダーとして機能するため、パイプラインをカスタマイズしたり、機密情報を安全に保存したりできるほか、CI/CD設定を管理しやすくなります。\n\n\n### CI/CD変数が重要な理由\n\n\nCI/CD変数の使用には、以下のような多くのメリットがあります。\n\n\n* **柔軟性** -\n主要なCI/CDスクリプトに手を加えることなく、さまざまな環境、設定、またはデプロイ対象にパイプラインを簡単に適応させられます。  \n * **セキュリティ** - API キー、パスワード、トークンのような機密情報を安全に保存して、コード内で直接公開されることのないようにします。  \n* **保守性** - 変数の値を一元化することで、CI/CDの設定がきれいに整理された状態に保たれるため、更新や修正作業を簡単に行えます。  \n\n* **再利用性** - 一度定義した変数は複数のプロジェクトで再利用できるため、重複が減り、一貫性を保ちやすくなります。\n\n\n### CI/CD変数のスコープ：プロジェクト、グループ、インスタンス\n\n\nGitLabでは、次のようなさまざまなスコープでCI/CD変数を定義し、その可視性と有効範囲を制御できます。\n\n\n* **プロジェクトレベルの変数** - 単一のプロジェクト専用の変数で、次のようなプロジェクト固有の設定を保存するのに適しています。\n  * デプロイURL：ステージング環境や本番環境向けのURLをそれぞれ定義します。  \n  * データベース認証情報：テストやデプロイ用のデータベース接続情報を保存します。  \n  * 機能フラグ：パイプラインのさまざまな段階で機能を有効または無効にします。  \n  * 例：\"MyWebApp\"というプロジェクトがあり、本番環境へのデプロイURLを保存したいとします。その場合、プロジェクトレベルで`DPROD_DEPLOY_URL`という名前の変数を作成し、`https://mywebapp.com`という値を格納します。  \n* **グループレベルの変数** -\nグループレベルの変数を作成すると、GitLabグループ内の全プロジェクトで共有されます。次のような複数のプロジェクトに共通する設定がある場合に便利です。\n\n  * 共有サービスのAPIキー：グループ内の複数のプロジェクトで使用されるサービス（AWS、Google Cloud、Docker Hubなど）のAPIキーを保存します。  \n  * グローバル構成設定：グループ内の全プロジェクトに適用される共通の設定パラメータを定義します。  \n  * 例：「Web Apps」というグループがあり、Docker Hub用にAPIキーを保存したいとします。その場合は、グループレベルで`DOCKER_HUB_API_KEY`という名前の変数を作成し、対応するAPIキーの値を格納します。  \n* **インスタンスレベルの変数** -\nGitLabインスタンスの全プロジェクトで利用可能な変数です。通常は、次のような組織全体に適用するグローバル設定がある場合に使用します。\n\n  * デフォルトのRunner登録トークン：新規[Runner](https://docs.gitlab.com/runner/)の登録時にデフォルトのトークンを提供します。  \n  * ライセンス情報：GitLabの機能やサードパーティツールのライセンスキー情報を保存します。  \n  * グローバル環境設定：全プロジェクトで利用可能な環境変数を定義します。  \n  * 例：GitLabインスタンス上の全プロジェクトにおいて、デフォルトのDockerイメージを設定したいとします。その場合、インスタンスレベルで`DEFAULT_DOCKER_IMAGE`という名前の変数を作成し、`ubuntu:latest`という値を格納します。\n\n### CI/CD変数を定義する\n\n\nCI/CD変数は以下の手順で定義できます。\n\n\n1. プロジェクト、グループ、またはインスタンスで、**設定 > CI/CD**ボタンの順にクリックします。  \n\n2. **変数**セクションに移動します。  \n\n3. **変数を追加**をクリックします。  \n\n4. **キー**（例：`API_KEY`）と**値**を入力します。  \n\n5.\n機密情報を扱う場合は、必要に応じて**変数を保護**ボックスをオンにします。オンにすると、保護ブランチまたは保護タグで実行されているパイプラインでのみ、変数が利用可能になります。  \n\n6. 必要に応じて、**変数をマスク**ボタンをオンにすると、ジョブログで変数の値が非表示になります。これにより、誤って公開されるのを防げます。  \n\n7. **変数を保存**をクリックします。\n\n\n### CI/CD変数を使用する\n\n\n`.gitlab-ci.yml`ファイルでCI/CD変数を使用する方法は簡単です。変数名の前にプレフィックスとして`$`を付けるだけです。\n\n\n```yaml\n\ndeploy_job:\n  script:\n    - echo \"Deploying to production...\"\n    - curl -H \"Authorization: Bearer $API_KEY\" https://api.example.com/deploy\n```\n\n\n### 定義済みのCI/CD変数\n\n\nGitLabでは、パイプラインでご利用いただけるように、[定義済みのCI/CD変数](https://docs.gitlab.com/ci/variables/predefined_variables/)を一式ご用意しています。これらの変数は、現在のパイプラインやジョブ、プロジェクトなどに関する情報を提供します。\n\n\nその中でも、使用されることの多い定義済み変数をいくつかご紹介します。\n\n\n* `$CI_COMMIT_SHA`：現在のパイプラインのコミットSHA。  \n\n* `$CI_PROJECT_DIR`：プロジェクトの複製先のディレクトリ。  \n\n* `$CI_PIPELINE_ID`：現在のパイプラインのID。  \n\n* `$CI_ENVIRONMENT_NAME`：デプロイ先の環境名（該当する場合）。\n\n\n### ベストプラクティス\n\n\n* 機密性の高い変数は安全に管理する：APIキーやパスワード、その他の機密情報を扱う場合は、保護およびマスクされた変数を使用しましょう。  \n\n* 値のハードコーディングは行わない：設定値を保存する際は変数を使用しましょう。そうすることで、パイプラインの柔軟性と保守性が高まります。  \n\n* 変数を整理する：変数をわかりやすい名前を付けて、関連する変数をまとめると、うまく整理できます。  \n\n* 適切なスコープを選ぶ：希望する変数の用途と可視性に基づいて、適切なスコープ（プロジェクト、グループ、またはインスタンス）を選びましょう。\n\n\n### 変数の力を最大限に活用する\n\n\nCI/CD変数は、GitLabパイプラインをカスタマイズし、保護するための強力なツールです。変数を使いこなし、各スコープを理解することで、より柔軟で保守しやすく、効率的なワークフローを作成できます。\n\n\n開発プロジェクトにおいて、GitLabの機能を活用していただくために必要な情報をお届けしました。ご紹介した情報がお役に立てば幸いです。\n\n\n> [Duo Enterpriseが搭載されたGitLab\nUltimateの無料トライアル](https://about.gitlab.com/ja-jp/free-trial/)に今すぐ申し込んで、CI/CD変数を早速ご利用ください。\n\n\n## 「GitLab入門」シリーズ\n\n「GitLab入門」シリーズのその他の記事もぜひご覧ください。\n\n\n-\n[ユーザーの管理方法](https://about.gitlab.com/ja-jp/blog/getting-started-with-gitlab-how-to-manage-users/)\n\n- \n[GitLabへのプロジェクトのインポート方法](https://about.gitlab.com/blog/getting-started-with-gitlab-how-to-import-your-projects-to-gitlab/)  \n\n-\n[プロジェクト管理を極める](https://about.gitlab.com/blog/getting-started-with-gitlab-mastering-project-management/)\n\n- [gitlab-triage\ngemを使ったアジャイルワークフローの自動化](https://about.gitlab.com/blog/automating-agile-workflows-with-the-gitlab-triage-gem/)\n\n-\n[CI/CDについて理解する](https://about.gitlab.com/blog/getting-started-with-gitlab-understanding-ci-cd/)\n",[730,681,680,9,109,678],{"slug":772,"featured":91,"template":685},"getting-started-with-gitlab-working-with-ci-cd-variables","content:ja-jp:blog:getting-started-with-gitlab-working-with-ci-cd-variables.yml","Getting Started With Gitlab Working With Ci Cd Variables","ja-jp/blog/getting-started-with-gitlab-working-with-ci-cd-variables.yml","ja-jp/blog/getting-started-with-gitlab-working-with-ci-cd-variables",{"_path":778,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":779,"content":785,"config":794,"_id":796,"_type":14,"title":797,"_source":16,"_file":798,"_stem":799,"_extension":19},"/ja-jp/blog/how-to-keep-up-with-ci-cd-best-practices",{"title":780,"description":781,"ogTitle":780,"ogDescription":781,"noIndex":6,"ogImage":782,"ogUrl":783,"ogSiteName":668,"ogType":669,"canonicalUrls":783,"schema":784}," CI/CDとは？ベストプラクティスやメリットも解説","CI/CDは高品質のアプリをスピーディに開発するのに最適です。注目度が高まるCI/CDとは何か、メリットやベストプラクティスについても説明します。","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749661856/Blog/Hero%20Images/ci-cd-demo.jpg","https://about.gitlab.com/blog/how-to-keep-up-with-ci-cd-best-practices","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \" CI/CDとは？ベストプラクティスやメリットも解説\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2022-02-03\",\n      }",{"title":780,"description":781,"authors":786,"heroImage":782,"date":788,"body":789,"category":790,"tags":791,"updatedDate":793},[787],"Valerie Silverthorne","2022-02-03","## 目次\n* CI/CDとは\n* CI/CDのメリット\n* CI/CDのベストプラクティス\n* CI/CDの成果を検討する方法\n* CI/CDパイプラインとは？\n* CI/CDツールの選び方\n* 多くの企業がGitLabのCI/CDを選ぶ理由とは？\n* 結論\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、高品質のアプリケーション・システム開発をよりスピーディに行うだけでなく、エラー削減やコストカットにも効果的です。しかしながら日本ではまだまだ知名度が低く、利用している企業は一握りというのが現状です。\n\n本記事では、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)とは何かについてわかりやすく解説するとともに、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)のメリットやベストプラクティスについて紹介します。\n\n## CI/CDとは\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、[継続的インテグレーション（Continuous Integration）](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)と継続的デリバリー（Continuous Delivery）の略称です。それぞれについて詳しく説明します。\n\n### CI（継続的インテグレーション）\n\n[CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)とは、開発者がコードを修正しそれをリポジトリにプッシュした際に、自動的にビルドやテストを実行するプロセスや仕組みのことです。[CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)によって継続的にテストを行うことで、コードの品質を高く保つことができます。\n\n### CD（継続的デリバリー）\n\nCDは、[CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)による統合や一体化をさらに拡張したもので、より高度にかつ自動的にシステムに変更が反映されるように設計された環境や概念を指します。\n\n### CI/CDの考え方\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、分割されているツールやプラットフォームを統合し、1つの変更が自動的に他ツールに反映されるように環境を組むことであり、アプリケーション開発の効率化を図ることです。ツールやプラットフォームを指すこともあれば、手法や概念として用いられることもあります。\n\n近年は著しい変化を伴う環境の中での開発が求められており、開発中に急に変更が生じることも多々あります。従来のウォーターフォール型の開発手法では急な変化に対応できず、常に変更とテストを繰り返しながら開発を進めていく[アジャイル開発](https://about.gitlab.com/ja-jp/solutions/agile-delivery/)が主流となっています。\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、ビルド、テスト、デプロイ、インフラストラクチャのプロビジョニングなどを一体化し、これまで手動で実施していた介入のほとんどを自動化します。アジャイル開発や近年注目が集まる[DevOps](https://about.gitlab.com/ja-jp/platform/)とマッチしており、開発環境の改善を図りたい企業に積極的に採用されています。\n\n今後、よりスピーディで高品質の開発を進めていきたいのであれば、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)環境や考え方を積極的に取り入れていく必要があるでしょう。\n\n## CI/CDのメリット\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)のメリットは以下の通りです。\n\n* 制作物の品質が高まる\n* 開発スピードが向上する\n* ツール間のズレを予防できる\n* デベロッパーが開発に集中できる\n\n### 制作物の品質が高まる\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を利用することで、ソフトウェアやアプリなどの品質が高まります。\n\n従来であれば、最新のバージョンを適用するのに数時間もしくは数日かかるため、アップデートやツール追加などが容易に行えない状況がありました。\n\n一方[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、最新のコードやテクノロジー適用が容易です。開発環境を常に最新に保つことができるため、最先端・高品質の制作物が期待できます。\n\n### 開発スピードが向上する\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)はツール間で連携されており、入力情報が他ツールに自動的に適用されるため、作業量が必然的に少なくなります。これにより、開発スピードが格段に高まるとともに、急な変化にも対応しやすくなります。\n\n### 環境の差異による問題を予防できる\n\n複数の開発環境を利用する場合、環境ごとの仕様が原因でエラーが生じたり、セキュリティに問題が発生したりすることがありました。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、各ツールが自動的に連携されているため、環境の際による問題が予防でき、それによるエラーやセキュリティ問題が減少します。エラーが少なくなれば人的コストを大幅にカットできるため、予算削減にもつながります。\n\n### デベロッパーが開発に集中できる\n\nデベロッパーの仕事は「開発」です。しかしながら、実際にはエラーやバグの修正に追われ、開発に専念しづらい状況が発生しています。\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ではエラーが発生しにくいため、これまでエラー対応にあてていた時間を開発に注げるようになります。デベロッパーのエンゲージメントが向上し、長期にわたって貢献してくれる土台が作られます。\n\n## CI/CDのベストプラクティス\n\n新しく[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を導入する場合には、これから紹介するベストプラクティスを実施することで、効果をより高められます。\n\n### コードの品質を管理する\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、ビルド、テスト、デプロイまで、同じコードを用いて開発を進めていきます。そのため、初期でコードの間違いがあった場合には、それが後半まで影響を与えます。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、通常の開発以上に、コードの適切な利用が重要です。\n\nデベロッパー間で認識の違いが生じないように、コートレポジトリを適切に作成・管理してください。また、定期的にコードレビューを行うとともに、コードの変更を行う際にはレポジトリの書き換えも必ず行うようにしてください。\n\n### 初期は微調整を頻繁に行う\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、一度組織にフィットすると、開発スピード向上やエラー削減に大きく貢献します。しかしながら、新規に導入した[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)をいきなり組織にフィットさせることは稀です。多くの企業が、実践とフィードバックを繰り返しながら、自社に最適化させていくプロセスを経験しています。\n\nそのため、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を取り入れる際には、デベロッパーからの声を丁寧に拾い上げる仕組みを作り上げることが重要です。何に困っているのか、どの部分がうまく機能していないのかを確認しながら、必要に応じて[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を微調整していくことで、自社に真にマッチしたCI/CDへと改良されていきます。\n\n### 適切なセキュリティ対策を行う\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、ビルド、テスト、デプロイが1つの環境で行える一方で、情報が外部に漏れた場合には、制作物すべてに影響を及ぼす可能性があります。そのため、セキュリティ対策はより強固に行う必要があります。\n\nログイン情報を不特定多数に共有しないようにするとともに、ログイン時の認証を強化する、ツールは最小限に抑える、問題発生時のリスクマネジメントを決めておくなど、セキュリティ対策には力を入れるようにしてください。\n\n### 設定ファイルを再利用する\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、設定ファイルに記述されたコードを繰り返し利用することで、開発時間の短縮とエラーやバグの削減を可能にしています。しかしながら、デベロッパーの人数が増えると情報共有が上手くいかず、設定ファイルの情報を用いずに開発を進めてしまう場合があるようです。これでは、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)のメリットを最大限に活かせません。\n\n組織として、設定ファイルをどのように活用すべきかを明確化するとともに、見やすい場所に設置しておく、定期的に情報共有するなど、対策を図るようにしてください。\n\n### 気づいたエラーを放置しない\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、コードを複数箇所に自動的に反映させることで、高速化とエラー減を実現しています。しかしながら、もし初期に利用したコードにエラーがあった場合、それがその他の箇所にも影響を及ぼします。エラーに気づいたら、すぐに修正を図るようにしてください。\n\n### デプロイごとに本番前環境をクリーンアップする\n\n環境の実行期間が長くなるほど、適用されたすべての構成変更と更新を追跡することが難しくなります。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、デプロイごとに本番前環境をクリーンアップすることで、以前のデータが悪さするのを防げます。不要なファイルやデータ、一時ファイル、ログなどを毎回削除するようにしてください。\n\n## CI/CDの成果を検討する方法\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を導入した場合には、以下の項目を用いて、成果を適切に検討するようにしてください。\n\n### サイクルタイム\n\nサイクルタイムは、1つの作業の工程開始から完了までにかかる時間です。コードの書き始めからアプリ完成までの時間を計測し、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)導入の前後で比較します。ただし、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)に変更して初回のアプリ開発は当然時間がかかるため、ある程度慣れてきたころのサイクルタイムを用いて比較するようにしてください。\n\n### 作業時間\n\nデベロッパーが何にどのぐらいの時間を費やしているのかを記録、分析します。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)がうまく機能し始めると、問題の処理やツール間の調整にかかる時間が減り、メインとなる開発にかけられる時間が増えます。もしその傾向があるのならば、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)のメリットをうまく享受できていると考えてよいでしょう。\n\n### エラー率\n\nアプリケーション開発においてエラー発生は避けられません。しかしながら、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)導入前後でエラー率がどの程度変わったのかを追跡することには大きな意味があります。もし[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)導入後にもエラーが大量に発生している、もしくはエラー修正にかかる作業時間が削減されていない場合、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)がうまく機能していない可能性があるため、見直しが必要です。\n\n### インフラコスト\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)導入にかかる費用を適切に把握するとともに、パフォーマンスとコストを見比べ、導入が適切であったかどうかを検討します。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は様々なメリットがある反面、当然のことながらインフラストラクチャ構築費用がかかります。開発スピードやエラー率、人件費などを見比べながら、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)導入がコスト面からみて妥当かどうかを検討してください。\n\n### チームの声\n\n実際に作業を行うデベロッパーの声も大切な評価基準です。ツールが使いやすいか、実際にエラーが少なくなったと感じるか、デベロッパー同士の連携に問題ないかなどを質問することで、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)が開発者目線から見てどうかを把握できます。\n\n## CI/CDパイプラインとは？\n\nパイプラインは特定のものをつなぐパイプです。例えば、AとBという別のものがある場合、パイプラインがない場合にはそれぞれが独立して機能します。一方、AとBがパイプで結ばれている場合、AとBがそれぞれ干渉しあい、影響し合うことで様々なメリット・デメリットを生み出します。\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)では、様々なステージや環境、ツールなどをパイプラインで結ぶことで自動化を図り、作業の効率化やエラーの削減、アップデートの容易化などを図ります。例えば、通常であればそれぞれ独立している「ビルド」「テスト」「デプロイ」の各ステージをパイプラインで結び付けることで、特定の変更が他のステージにおいても自動的に反映されます。[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)パイプラインは、CI/CDが効果を発揮する上での核となる考え方や構造です。\n\nこのパイプラインが正しく機能しているプラットフォームやツールを利用することで、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)のメリットを最大限に享受できます。\n\n一方で、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)パイプラインがうまく機能しない場合、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)の恩恵を受けられないばかりか、エラーが増えたり、余計に時間がかかったりする場合があります。そのため、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールの選定は慎重に行う必要があります。\n\n## CI/CDツールの選び方\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)を導入する目的は、開発サイクル全体にわたって包括的なフィードバックを提供しながら、正確で信頼性の高い製品を迅速に生成することです。そのため、正確性、信頼性、速度の面で優れた[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールを探す必要があります。\n\nまた、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールの導入は、デベロッパーにとって大きな変化になるのに加え、インフラコストも発生します。そのため、環境をいきなり変えてしまうのではなく、まずは無料トライアルがある[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールを利用し、使用感を確認するようにしてください。\n\nGitLabでは、優れた性能の[CI/CDパイプライン](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)を提供しています。[無料トライアル](https://about.gitlab.com/free-trial/)も受け付けているため、お気軽にお問い合わせください。\n\n## 多くの企業がGitLabのCI/CDを選ぶ理由とは？\n\n多くの[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールは、CIとCDを別々のツールで管理し、それを結びつけることでCI/CDを実現しています。一方、GitLabは長年の[DevOpsプラットフォーム](https://about.gitlab.com/ja-jp/platform/)の提供経験をもとに、ビルドーテストーデプロイが一体となった[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールの提供を行っています。\n\nGitLabツールであれば、他社のツールとの結合を一切考慮することなく、すべて[1つのツール内で完結](https://about.gitlab.com/ja-jp/devsecops/)できます。\n\n## 結論\n\n[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)は、近年重要性が高まっているアプリケーション開発のスピーディ化を実現するために非常に重要です。日本ではまだまだ導入企業が少ないものの、世界ではスタンダードになりつつあります。もし世界水準での開発環境を整えたければ、[CI/CD](https://about.gitlab.com/ja-jp/topics/ci-cd/)ツールの導入を少しでも早く検討するとよいでしょう。\n\n*監修：大井 雄介 [@yoi_gl](https://gitlab.com/yoi_gl)\n（GitLab合同会社 ソリューションアーキテクト本部 本部長）*","insights",[680,9,792],"DevOps","2024-11-06",{"slug":795,"featured":6,"template":685},"how-to-keep-up-with-ci-cd-best-practices","content:ja-jp:blog:how-to-keep-up-with-ci-cd-best-practices.yml","How To Keep Up With Ci Cd Best Practices","ja-jp/blog/how-to-keep-up-with-ci-cd-best-practices.yml","ja-jp/blog/how-to-keep-up-with-ci-cd-best-practices",{"_path":801,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":802,"content":808,"config":815,"_id":817,"_type":14,"title":818,"_source":16,"_file":819,"_stem":820,"_extension":19},"/ja-jp/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"title":803,"description":804,"ogTitle":803,"ogDescription":804,"noIndex":6,"ogImage":805,"ogUrl":806,"ogSiteName":668,"ogType":669,"canonicalUrls":806,"schema":807},"子パイプラインを使用して5つの環境に継続的にデプロイする","使用するGitLabワークフローを最小限に抑えつつ、複数の環境（事前の準備なしに一時的に利用できるsandboxなど）への継続的デプロイを管理する方法を解説します。","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097012/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_397632156_3Ldy1urjMStQCl4qnOBvE0_1750097011626.jpg","https://about.gitlab.com/blog/using-child-pipelines-to-continuously-deploy-to-five-environments","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"子パイプラインを使用して5つの環境に継続的にデプロイする\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Olivier Dupré\"}],\n        \"datePublished\": \"2024-09-26\",\n      }",{"title":803,"description":804,"authors":809,"heroImage":805,"date":811,"body":812,"category":676,"tags":813,"updatedDate":814},[810],"Olivier Dupré","2024-09-26","DevSecOpsチームでは、複数の環境にまたがる継続的デプロイを管理する機能が必要となることがあります。その場合、ワークフローを変更せずに、デプロイを行えるようにする必要があります。[GitLab\nDevSecOpsプラットフォーム](https://about.gitlab.com/)なら、事前の準備なしに一時的に利用できるsandboxを使用して工数を最小限に抑えるアプローチなどを通じて、こうしたニーズに対応できます。この記事では、Terraformを使って複数の環境上でインフラの継続的デプロイを行う方法についてご紹介します。\n\n\nこの手法は、[Pulumi](https://www.pulumi.com/)や[Ansible](https://www.ansible.com/)のような別の技術を使用したInfrastructure\nas\nCode（IaC）でも、どのような言語で書かれたソースコードでも、または多様な言語が混在するモノレポであっても、あらゆるプロジェクトに簡単に適用できます。\n\n\nこのチュートリアルの終了時には、以下のような環境をデプロイするパイプラインが完成します。\n\n\n* 各フィーチャーブランチの一時的な**レビュー（review）**環境。\n\n* 簡単に消去可能で、mainブランチからデプロイされる**統合（integration）**環境。\n\n* **品質管理（qa）**環境。同様にmainブランチからデプロイされ、品質管理プロセスを実行します。\n\n* タグ付けされるたびにデプロイされる**ステージング（staging）**環境。これは本番環境前の最後のステージです。\n\n*\nステージング環境の直後の**本番（production）**環境。今回はデモ用に手動でトリガーしますが、継続的にデプロイされるようにすることも可能です。\n\n\n>この記事で使用されるフローチャートの説明は以下のとおりです。\n\n> * 角が丸いボックスはGitLabブランチです。\n\n> * 四角のボックスは環境です。\n\n> * 矢印上のテキストは、あるボックスから次のボックスへのアクションを指します。\n\n> * ひし形のボックスは決定ステップです。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    A(main) -->|新機能| B(feature_X)\n\n    B -->|自動デプロイ| C[review/feature_X]\n    B -->|マージ| D(main)\n    C -->|破棄| D\n\n    D -->|自動デプロイ| E[integration]\n    E -->|手動| F[qa]\n\n    D -->|タグ付け| G(X.Y.Z)\n    F -->|検証| G\n\n    G -->|自動デプロイ| H[staging]\n    H -->|手動| I{plan}\n    I -->|手動| J[production]\n\u003C/pre>\n\n\nステップごとに、[理由](#why)と[行うこと](#what)を説明した上で、[方法](#how)をご紹介します。これにより、このチュートリアルを完全に理解し、正確に実行しやすくなります。\n\n\n## 理由\n\n\n*\n[継続的インテグレーション](https://about.gitlab.com/topics/ci-cd/#what-is-continuous-integration-ci)はほぼ事実上の業界標準と言えます。ほとんどの企業は、CIパイプラインを実装済みであるか、その実践の標準化を検討しています。\n\n\n*\nまた、CIパイプラインの最後にリポジトリまたはレジストリにアーティファクトをプッシュする[継続的なデリバリー](https://about.gitlab.com/topics/ci-cd/#what-is-continuous-delivery-cd)も一般的です。\n\n\n*\n継続的デプロイメントはさらに進んで、これらのアーティファクトを自動的にデプロイしますが、その普及はまだ限定的です。導入されている場合、主にアプリケーション分野で見られます。インフラの継続的デプロイメントに関しては、状況がやや不明瞭で、複数の環境の管理に重きが置かれる傾向があります。一方で、インフラのコードをテストし、セキュリティを確保し、検証することはより難しいとされています。この分野は、DevOpsがまだ成熟に至っていない分野のひとつです。ほかの分野としては、セキュリティのシフトレフトが挙げられます。具体的には、セキュリティチームの介入、さらに重要なことに、セキュリティ上のリスクへの対応をデリバリーライフサイクルの早期に組み込み、DevOpsから***DevSecOps***へと発展させる取り組みのことです。\n\n\nこのような概況を踏まえ、本チュートリアルでは、インフラにDevSecOpsをシンプルかつ効果的に導入するシナリオに取り組みます。5つの環境にリソースをデプロイする例を交えながら、開発から本番環境へと段階的に進めていきます。\n\n\n__注__：個人的にはFinOpsアプローチを採用し、環境の数を減らすことを推奨していますが、開発環境、ステージング環境、本番環境以外の環境を保持すべき場合もあります。そのため、これからご紹介する例をご自身のニーズに合わせて調整してください。\n\n\n## 行うこと\n\n\nクラウド技術の台頭により、IaCの利用が促進されています。この分野を最初に開拓したのは、AnsibleとTerraformでした。OpenTofu、Pulumi、AWS\nCDK、Google Deploy Managerを始めとする多くの会社がその後に続きました。\n\n\nIaCを定義することは、インフラストラクチャを安全にデプロイするのに最適なソリューションです。目標を達成できるまで必要なだけ、テスト、デプロイ、再実行を繰り返し行えます。\n\n\n残念なことに、ターゲット環境ごとに複数のブランチやリポジトリを保持している企業がよくあります。これが原因で問題が生じます。こういった企業では、プロセスの実施が徹底されていません。本番環境のコードベースへの変更が、その前の環境で正しくテストされているかどうかも確認できません。その結果、ある環境から別の環境へ流れるだけになります。\n\n\nこのチュートリアルが必要だと気づいたのは、あるカンファレンスに参加した際に、本番環境へのデプロイ前にインフラストラクチャを十分にテストするワークフローがないと参加者全員から聞いたときです。みなが、本番環境で直接コードにパッチを適用することもあると言っていました。確かにこの方法は手っ取り早いですが、果たして安全でしょうか？前の環境にフィードバックをどう戻すのでしょうか？また副次効果が生じないようにするにはどうすればよいのでしょうか？新たな脆弱性が本番環境にあまりにも早くプッシュされることで会社がリスクにさらされないようにするには、どのように管理すべきでしょうか？\n\n\nここで重要なのは、DevOpsチームが本番環境に直接デプロイするのは*なぜ*かということです。パイプラインの効率性や速度を向上できる可能性があるためでしょうか？自動化できないのでしょうか？それどころか、*本番環境以外で正確にテストする方法がない*からなのでしょうか？\n\n\n次のセクションでは、インフラストラクチャを自動化し、ほかの人に影響を及ぼす環境にコードがプッシュされる前に、DevOpsチームが効果的かつ確実にテストを実施するための方法をご説明します。また、コードがどのように保護され、エンドツーエンドでデプロイが管理されているかも確認していきます。\n\n\n## 方法\n\n\n前述のとおり、現在では多くのIaC言語が存在しているため、この記事だけで客観的に*すべて*を取り上げることはできません。そのため、この記事ではバージョン1.4で実行される基本的なTerraformコードを使用します。IaC言語そのものではなく、貴社のエコシステムに適用できるプロセスに注目してください。\n\n\n### Terraformコード\n\n\nまずは、基本的なTerraformコードから始めましょう。\n\n\n仮想ネットワークであるAWSの仮想プライベートクラウド（VPC）にデプロイしたいと思います。VPCには、パブリックサブネットとプライベートサブネットをデプロイします。名前からわかるように、これらはメインVPCのサブネットです。最後に、パブリックサブネットにAmazon\nElastic Cloud Compute（EC2）インスタンス（仮想マシン）を追加します。\n\n\nこれは、比較的簡単な方法で4つのリソースをデプロイする方法を示しています。コードではなく、パイプラインに焦点を当てることがここでの目的です。\n\n\nここで目指すリポジトリの完成形は、以下のとおりです。\n\n\n![リポジトリの完成図](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750097033415.png)\n\n\nステップごとに行っていきましょう。\n\n\nまずは、`terraform/main.tf`ファイルでリソースをすべて宣言します。\n\n\n```terraform\n\nprovider \"aws\" {\n  region = var.aws_default_region\n}\n\n\nresource \"aws_vpc\" \"main\" {\n  cidr_block = var.aws_vpc_cidr\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n\n\nresource \"aws_subnet\" \"public_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_public_subnet_cidr\n\n  tags = {\n    Name = \"Public Subnet\"\n  }\n}\n\nresource \"aws_subnet\" \"private_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_private_subnet_cidr\n\n  tags = {\n    Name = \"Private Subnet\"\n  }\n}\n\n\nresource \"aws_instance\" \"sandbox\" {\n  ami           = var.aws_ami_id\n  instance_type = var.aws_instance_type\n\n  subnet_id = aws_subnet.public_subnet.id\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n\n```\n\n\nご覧のとおり、このコードではいくつかの変数が必要となるため、`terraform/variables.tf`ファイルでそれらを宣言します。\n\n\n```terraform\n\nvariable \"aws_ami_id\" {\n  description = \"The AMI ID of the image being deployed.\"\n  type        = string\n}\n\n\nvariable \"aws_instance_type\" {\n  description = \"The instance type of the VM being deployed.\"\n  type        = string\n  default     = \"t2.micro\"\n}\n\n\nvariable \"aws_vpc_cidr\" {\n  description = \"The CIDR of the VPC.\"\n  type        = string\n  default     = \"10.0.0.0/16\"\n}\n\n\nvariable \"aws_public_subnet_cidr\" {\n  description = \"The CIDR of the public subnet.\"\n  type        = string\n  default     = \"10.0.1.0/24\"\n}\n\n\nvariable \"aws_private_subnet_cidr\" {\n  description = \"The CIDR of the private subnet.\"\n  type        = string\n  default     = \"10.0.2.0/24\"\n}\n\n\nvariable \"aws_default_region\" {\n  description = \"Default region where resources are deployed.\"\n  type        = string\n  default     = \"eu-west-3\"\n}\n\n\nvariable \"aws_resources_name\" {\n  description = \"Default name for the resources.\"\n  type        = string\n  default     = \"demo\"\n}\n\n```\n\n\nすでにIaC側に関しては、これでほぼ準備が整いました。しかしながら、これではTerraformの状態を共有できません。ご存知ない方のために大まかに説明すると、Terraformは以下を行うことで動作します。\n\n\n* `plan`により、インフラストラクチャの現在の状態とコートで定義されている内容の差分を確認してから、差分を出力します。\n\n* `apply`により、`plan`の差分を適用して、状態を更新します。\n\n\n最初のラウンドでは状態は空で、その後、Terraformによって適用されたリソースの詳細（IDなど）が挿入されます。\n\n\n問題は、その状態がどこに保存されるかということです。また、複数のデベロッパーがコード上で共同作業を行えるようにするにはどうすればよいのでしょうか？\n\n\n解決策はとても簡単で、GitLabを利用して、[Terraform\nHTTPバックエンド](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html)を介して状態を保存して共有するだけです。\n\n\nこのバックエンドを使用するには、まずはもっともシンプルな`terraform/backend.tf`ファイルを作成します。次のステップは、パイプラインで処理します。\n\n\n```terraform\n\nterraform {\n  backend \"http\" {\n  }\n}\n\n```\n\n\nこれで、4つのリソースをデプロイするための最低限のTerraformコードができあがりました。変数の値は実行する際に指定するので、後でご説明します。\n\n\n### ワークフロー\n\n\nこれから以下のワークフローを実装します。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    A(main) -->|新機能| B(feature_X)\n\n    B -->|自動デプロイ| C[review/feature_X]\n    B -->|マージ| D(main)\n    C -->|破棄| D\n\n    D -->|自動デプロイ| E[integration]\n    E -->|手動| F[qa]\n\n    D -->|タグ付け| G(X.Y.Z)\n    F -->|検証| G\n\n    G -->|自動デプロイ| H[staging]\n    H -->|手動| I{plan}\n    I -->|手動| J[production]\n\u003C/pre>\n\n\n1.\n**フィーチャー**ブランチを作成します。これにより、コードに対して継続的にすべてのスキャナーが実行され、コンプライアンスとセキュリティを確保できます。このコードは、現在のブランチの名前が付けられた一時的な環境`review/feature_branch`に継続的にデプロイされます。これは、デベロッパーと運用チームが誰にも影響を与えることなくコードをテストできる安全な環境です。また、ここでコードレビューやスキャナーの実行などのプロセスを実施し、コードの品質とセキュリティが許容範囲内であることを確認し、資産が危険にさらされることのないようにします。このブランチでデプロイされたインフラストラクチャは、ブランチが閉じられると自動的に破棄されます。これにより予算範囲内に収めやすくなります。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    A(main) -->|新機能| B(feature_X)\n\n    B -->|自動デプロイ| C[review/feature_X]\n    B -->|マージ| D(main)\n    C -->|破棄| D\n\u003C/pre>\n\n\n2.\n承認されると、フィーチャーブランチはmainブランチに**マージ**されます。これは[保護ブランチ](https://docs.gitlab.com/ee/user/project/protected_branches.html)であり、誰もプッシュできません。本番環境への変更リクエストをすべて十分にテストするために必要です。このブランチも継続的にデプロイされます。ここでのターゲットは`integration`環境です。この環境をもう少し安定させるために、削除は自動化されておらず、手動でトリガーできるようになっています。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    D(main) -->|自動デプロイ| E[integration]\n\u003C/pre>\n\n\n3.\nここから次のデプロイをトリガーするには、手動による承認が必要となります。これにより、mainブランチが`qa`環境にデプロイされます。ここでパイプラインからの削除を防ぐルールを設定します。何しろすでに3つ目のこの環境はかなり安定しているはずなので、このルールは誤って削除されるのを防ぐことを目的とします。貴社のプロセスに合わせて、お好きなようなルールを調整してください。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    D(main)-->|自動デプロイ| E[integration]\n    E -->|手動| F[qa]\n\u003C/pre>\n\n\n4.\n次に進むには、コードに**タグ付け**する必要があります。[保護タグ](https://docs.gitlab.com/ee/user/project/protected_tags.html)を使用して、特定のユーザーのみが最後の2つの環境にデプロイできるようにします。これにより、`staging`環境へのデプロイが即座にトリガーされます。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    D(main) -->|タグ付け| G(X.Y.Z)\n    F[qa] -->|検証| G\n\n    G -->|自動デプロイ| H[staging]\n\u003C/pre>\n\n\n5.\nついに`production`に到達しました。インフラストラクチャに関して言うと、（10%や25%など）段階的にデプロイするのは難しい場合が多いため、インフラストラクチャ全体をデプロイします。ただし、この最後のステップで行う手動トリガーで、このデプロイを制御します。そして、この極めて重要な環境を最大限に制御できるようにするために、[保護環境](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)として管理します。\n\n\n\u003Cpre class=\"mermaid\">\n\nflowchart LR\n    H[staging] -->|手動| I{plan}\n    I -->|手動| J[production]\n\u003C/pre>\n\n\n### パイプライン\n\n\n上記の[ワークフロー](#the-workflow)を実装するために、2つの[ダウンストリームパイプライン](https://docs.gitlab.com/ee/ci/pipelines/downstream_pipelines.html)とともにパイプラインを構築します。\n\n\n#### メインパイプライン\n\n\nまずは、メインパイプラインから始めましょう。メインパイプラインは、**フィーチャーブランチへのプッシュ**、**デフォルトブランチへのマージ**、または**タグ付け**が発生すると、必ず自動的にトリガーされます。*このパイプライン*によって、`dev`、`integration`、`staging`環境に対する真の**継続的デプロイ**を実現できます。プロジェクトのルートにある`.gitlab-ci.yml`ファイルで宣言します。\n\n\n![リポジトリのターゲット](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097033417.png)\n\n\n```yml\n\nStages:\n  - test\n  - environments\n\n.environment:\n  stage: environments\n  variables:\n    TF_ROOT: terraform\n    TF_CLI_ARGS_plan: \"-var-file=../vars/$variables_file.tfvars\"\n  trigger:\n    include: .gitlab-ci/.first-layer.gitlab-ci.yml\n    strategy: depend            # Wait for the triggered pipeline to successfully complete\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nreview:\n  extends: .environment\n  variables:\n    environment: review/$CI_COMMIT_REF_SLUG\n    TF_STATE_NAME: $CI_COMMIT_REF_SLUG\n    variables_file: review\n    TF_VAR_aws_resources_name: $CI_COMMIT_REF_SLUG  # Used in the tag Name of the resources deployed, to easily differenciate them\n  rules:\n    - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n\nintegration:\n  extends: .environment\n  variables:\n    environment: integration\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nstaging:\n  extends: .environment\n  variables:\n    environment: staging\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_TAG\n\n#### TWEAK\n\n# This tweak is needed to display vulnerability results in the merge\nwidgets.\n\n# As soon as this issue https://gitlab.com/gitlab-org/gitlab/-/issues/439700\nis resolved, the `include` instruction below can be removed.\n\n# Until then, the SAST IaC scanners will run in the downstream pipelines,\nbut their results will not be available directly in the merge request\nwidget, making it harder to track them.\n\n# Note: This workaround is perfectly safe and will not slow down your\npipeline.\n\ninclude:\n  - template: Security/SAST-IaC.gitlab-ci.yml\n#### END TWEAK\n\n\n```\n\n\nこのパイプラインは、`test`と`environments`の2つのステージのみを実行します。前者は、*TWEAK（微調整）*により、スキャナーを実行するために必要です。後者では、上記で定義したケース（ブランチへのプッシュ、デフォルトブランチへのマージ、タグ付け）ごとに異なる変数セットを持つ子パイプラインがトリガーされます。\n\n\nここで子パイプラインに[strategy:depend](https://docs.gitlab.com/ee/ci/yaml/index.html#triggerstrategy)キーワードで依存を追加します。これにより、デプロイの完了後にGitLabのパイプラインビューが更新されます。\n\n\nご覧のとおりベースとなるジョブが[無効になる](https://docs.gitlab.com/ee/ci/jobs/#hide-jobs)ように定義し、特定の変数とルールで拡張して、ターゲット環境ごとに単一のデプロイメントだけがトリガーされるようにしています。\n\n\n[定義済み変数](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)に加え、定義する必要がある新たな2つのエントリを使用します。\n\n1. 各環境[固有の変数](#the-variable-definitions)：`../vars/$variables_file.tfvars`\n\n2. [子パイプライン](#the-child-pipeline)。`.gitlab-ci/.first-layer.gitlab-ci.yml`で定義\n\n\nまずは、簡単な方、つまり変数の定義から始めましょう。\n\n\n### 変数の定義\n\n\nここでは、2つのソリューションを組み合わせてTerraformに変数を提供します。\n\n\n*\n1つ目は、[.tfvarsファイル](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files)を使用して、機密性の低い入力をすべて行う方法です。これはGitLab内に保存する必要があります。\n\n\n![Terraformに変数を提供するための1つ目のソリューション](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750097033419.png)\n\n\n*\n2つ目は、プレフィックスに`TF_VAR`を付けた[環境変数](https://developer.hashicorp.com/terraform/language/values/variables#environment-variables)を使用する方法です。変数を挿入するこの2つ目の方法は、[変数をマスク](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable)し、[保護](https://docs.gitlab.com/ee/ci/variables/#protect-a-cicd-variable)し、さらに[スコープの環境を設定する](https://docs.gitlab.com/ee/ci/environments/index.html#limit-the-environment-scope-of-a-cicd-variable)GitLabの機能とも関係する、**機密情報の漏えいを防ぐ**強力なソリューションです（本番環境のプライベートClassless\nInter-Domain\nRouting（CIDR）で非常に機密性が高いデータをやり取りすると考えられる場合は、この方法で保護すれば、本番環境、および保護ブランチやタグに対して実行されるパイプラインでのみ利用できるようにし、ジョブのログでその値がマスクされるようにすることができます）。\n\n\n![Terraformに変数を提供するための2つ目のソリューション](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750097033422.png)\n\n\nまた、各変数ファイルを変更できるユーザーを設定するために、[`CODEOWNERS`ファイル](https://docs.gitlab.com/ee/user/project/codeowners/)で各変数ファイルを管理する必要があります。\n\n\n```\n\n[Production owners] \n\nvars/production.tfvars @operations-group\n\n\n[Staging owners]\n\nvars/staging.tfvars @odupre @operations-group\n\n\n[CodeOwners owners]\n\nCODEOWNERS @odupre\n\n```\n\n\nこの記事は、Terraformのトレーニング用ではないため、詳しく説明せず、ここでは`vars/review.tfvars`ファイルを紹介するだけに留めます。当然ながら、これに続く環境ファイルもほぼ同じです。ここでは機密性の低い変数とその値を設定するだけです。\n\n\n```shell\n\naws_vpc_cidr = \"10.1.0.0/16\"\n\naws_public_subnet_cidr = \"10.1.1.0/24\"\n\naws_private_subnet_cidr = \"10.1.2.0/24\"\n\n```\n\n\n#### 子パイプライン\n\n\n実際の作業はこのパイプライン内で行われます。そのため、最初のパイプラインよりも少し複雑です。しかしながら、力を合わせれば何でも乗り越えられます！\n\n\n[メインパイプライン](#the-main-pipeline)の定義で説明したように、ダウンストリームパイプラインは`.gitlab-ci/.first-layer.gitlab-ci.yml`で宣言されています。\n\n\n![ファイルで宣言されているダウンストリームパイプライン](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750097033424.png)\n\n\n小さなステップに分けて説明します。最後に全体像が見えるはずです。\n\n\n##### Terraformコマンドを実行してコードを保護する\n\n\nまずは、Terraformのパイプラインを実行したいと思います。GitLabはオープンソースであるため、Terraform用のテンプレートもオープンソースです。そのため、このテンプレートを含めるだけで済みます。以下のスニペットを使用して行えます。\n\n\n```yml\n\ninclude:\n  - template: Terraform.gitlab-ci.yml\n```\n\n\nこのテンプレートは、planとapplyが行われる前に、Terraformによるフォーマットのチェックとコードの検証を実行します。デプロイしたものを破棄することもできます。\n\n\nさらに、GitLabは統合された単一のDevSecOpsプラットフォームであるため、このテンプレート内に2つのセキュリティスキャナーを自動的に組み込み、コード内の潜在的な脅威を検出し、次の環境にデプロイされる前に警告を発します。\n\n\nこれでコードの確認、保護、ビルド、デプロイが完了したので、いくつかの便利な技をご紹介します。\n\n\n##### ジョブ間でキャッシュを共有する\n\n\nジョブの結果をキャッシュして、後続のパイプラインジョブで再利用します。これはとても簡単で、以下のコードを追加するだけで行えます。\n\n\n```yml\n\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n```\n\n\nここでは、コミットごとに異なるキャッシュを定義し、必要に応じてmainブランチ名にフォールバックするようにします。\n\n\n使用しているテンプレートをよく見ると、ジョブの実行タイミングを制御するルールがあることがわかります。全ブランチですべての制御（QAとセキュリティの両方）を実行したいと思います。そのため、次にこれらの設定を上書きします。\n\n\n##### すべてのブランチで制御を実行する\n\n\nGitLabテンプレートは強力な機能で、テンプレートの一部のみを上書きできます。品質チェックとセキュリティチェックが必ず実行されるよう、一部のジョブのルールを上書きしたいと思います。これらのジョブ向けに定義するその他すべては、テンプレートで定義された内容のままにします。\n\n\n```yml\n\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - when: always\n\niac-sast:\n  rules:\n    - when: always\n```\n\n\nこれで品質とセキュリティの制御を実施できたため、[ワークフロー](#the-workflow)内のメインの環境（integrationとstaging）とreview環境の動作に違いを付けたいと思います。まずはメインの環境の振る舞いを定義し、review環境用にこの設定を微調整していきましょう。\n\n\n##### integrationとstaging環境への継続的デプロイ\n\n\n前述のように、この2つの環境にmainブランチとタグをデプロイしたいため、そのように制御するルールを`build`と`deploy`の両方のジョブに追加します。そして、`integration`環境でのみ`destroy`を有効にします。`staging`環境は重要度が高いため、ワンクリックで削除できないようにします。この操作はエラーを引き起こしやすく、避けたいと考えています。\n\n\n最後に、`deploy`ジョブを`destroy`ジョブにリンクして、GitLab GUIから直接環境を`stop`できるようにします。\n\n\nここで使用する`GIT_STRATEGY`は、破棄する際にRunner内のソースブランチからコードが取得されることを防ぎます。これは、ブランチが手動で削除された場合は失敗するため、キャッシュを使用して、Terraformの命令を実行するために必要なものすべてを取得します。\n\n\n```yml\n\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env\n(integration or staging) when merging to default branch or tagging. Second\nlayer environments (qa and production) will be controlled manually\n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n```\n\n前述のとおり、これは`integration`と`staging`環境へのデプロイというニーズに即しています。しかしながら、デベロッパーがほかの人に影響を及ぼさずに、自分のコードに触れて検証できる一時的な環境がまだ不足しています。そのため、次は`review`環境へのデプロイを行います。\n\n\n##### review環境への継続的デプロイ\n\n\nreview環境へのデプロイは、`integration`や`staging`環境へのデプロイと大差はありません。そこで、ここでもGitLabの機能を活用して、ジョブ定義の一部のみを上書きします。\n\n\nまずは、これらのジョブがフィーチャーブランチでのみ実行されるようルールを設定します。\n\n\n次に、`deploy_review`ジョブを`destroy_review`ジョブにリンクします。これにより、GitLabユーザーインターフェイスから**手動で**環境を停止できるようになりますが、さらに重要なのは、フィーチャーブランチの完了時に**環境の破棄が自動的にトリガー**されるようになります。これは、運用にかかる費用を抑えるのに効果的な、優れたFinOpsプラクティスです。\n\n\nTerraformでは、インフラストラクチャの構築時と同様に、破棄する際にもplanファイルが必要なため、`destroy_review`から`build_review`に依存を追加して、そのアーティファクトを取得します。\n\n\n最後に、ご覧のとおり、環境の名前を`$environment`に設定します。これは、[メインパイプライン](#the-main-pipeline)で`review/$CI_COMMIT_REF_SLUG`に設定され、`trigger:forward:yaml_variables:true`という命令により、その子パイプラインに転送されます。\n\n\n```yml\n\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n```\n\n\nさて、まとめると、これで次のことを行うパイプラインができました。\n\n\n* 一時的なreview環境へのデプロイ。フィーチャーブランチの完了時に、自動的にクリーンアップされます\n\n* **デフォルトブランチ**から`integration`への継続的デプロイ\n\n* **タグ**から`staging`への継続的デプロイ\n\n\nさらにレイヤを追加し、今回は手動でのトリガーをもとに`qa`と`production`環境にデプロイされるようにしましょう。\n\n\n##### qaとproduction環境への継続的デプロイ\n\n\n誰もが本番環境に継続的デプロイしたいわけではないため、次の2つのデプロイには手動による検証を追加します。単に**CD**の観点で考えた場合、このトリガーを追加することはありませんが、ほかのトリガーからジョブを実行する方法を学ぶ機会として捉えてください。\n\n\nこれまでデプロイを実行する際は、必ず[メインパイプライン](#the-main-pipeline)から[子パイプライン](#the-child-pipeline)を開始してきました。\n\n\nデフォルトブランチとタグからさらにデプロイを実行したいため、これらの追加ステップ用に別のレイヤを追加します。新たな手順は必要ありません。[メインパイプライン](#the-main-pipeline)で行ったのとまったく同じプロセスを再度繰り返します。この方法だと、必要な数だけレイヤを操作できます。中には最大で9つの環境がある例も見たことがあります。環境の数を抑えることの利点についてはあらためて説明しませんが、このプロセスを使用することで、初期段階から最終的なデリバリーまで、同じパイプラインを非常に簡単に実装できます。その上、パイプラインの定義をシンプルに保ちつつ、コストをかけずに維持できる小さな塊に分割可能です。\n\n\nここでは変数の競合を防ぐために、新しいvar名を使用してTerraformの状態と入力ファイルを識別しています。\n\n\n```yml\n\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n```\n\n\n**ここで重要なテクニックは、新しいダウンストリームパイプラインに使用するstrategyの設定です。**`trigger:strategy`はデフォルトの値のままにしておきます。そうしなければ、[メインパイプライン](#the-main-pipeline)は、[孫パイプライン](#the-grand-child-pipeline)が完了するまで待機することになります。手動トリガーだと、非常に長い時間かかり、パイプラインダッシュボードが読みづらく、理解しにくくなる可能性があります。\n\n\nここでインクルードした`.gitlab-ci/.second-layer.gitlab-ci.yml`ファイルが何なのか疑問に感じた方もいらっしゃるかもしれません。こちらは次のセクションで説明します。\n\n\n##### 1つ目のレイヤのパイプラインに関する全定義\n\n\n1つ目のレイヤの全詳細（`.gitlab-ci/.first-layer.gitlab-ci.yml`に保存）を確認したい場合は、以下のセクションを参照してください。\n\n\n```yml\n\nvariables:\n  TF_VAR_aws_ami_id: $AWS_AMI_ID\n  TF_VAR_aws_instance_type: $AWS_INSTANCE_TYPE\n  TF_VAR_aws_default_region: $AWS_DEFAULT_REGION\n\ninclude:\n  - template: Terraform.gitlab-ci.yml\n\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n  - cleanup\n  - 2nd_layer       # Use to deploy a 2nd environment on both the main branch and on the tags\n\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\niac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\n###########################################################################################################\n\n## Integration env. and Staging. env\n\n##  * Auto-deploy to Integration on merge to main.\n\n##  * Auto-deploy to Staging on tag.\n\n##  * Integration can be manually destroyed if TF_DESTROY is set to true.\n\n##  * Destroy of next env. is not automated to prevent errors.\n\n###########################################################################################################\n\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env\n(integration or staging) when merging to default branch or tagging. Second\nlayer environments (qa and production) will be controlled manually\n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n###########################################################################################################\n\n\n###########################################################################################################\n\n## Dev env.\n\n##  * Temporary environment. Lives and dies with the Merge Request.\n\n##  * Auto-deploy on push to feature branch.\n\n##  * Auto-destroy on when Merge Request is closed.\n\n###########################################################################################################\n\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n###########################################################################################################\n\n\n###########################################################################################################\n\n## Second layer\n\n##  * Deploys from main branch to qa env.\n\n##  * Deploys from tag to production.\n\n###########################################################################################################\n\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n###########################################################################################################\n\n```\n\n\nこの段階で、すでに3つの環境に問題なくデプロイしています。個人的にはこのアプローチが理想的でおすすめです。ただし、もっと多くの環境が必要であれば、CDパイプラインに追加してください。\n\n\n`trigger:include`というキーワードでダウンストリームパイプラインをインクルードしていることはすでにお気づきだと思います。これにより、`.gitlab-ci/.second-layer.gitlab-ci.yml`ファイルがインクルードされます。ほぼ同じパイプラインを実行したいため、当然ながら先ほど詳しく説明したものと内容は非常に似ています。ここで[孫パイプライン](#the-grand-child-pipeline)を定義する主な利点は、それ自体が独立しているため、変数やルールを非常に定義しやすくことです。\n\n\n### 孫パイプライン\n\n\nこの2つ目のレイヤとなるパイプラインは、まったく新しいパイプラインです。そのため、1つ目のレイヤの定義を模倣しつつ、以下を行う必要があります。\n\n\n* [Terraformテンプレートのインクルード](#run-terraform-commands-and-secure-the-code)。\n\n*\n[セキュリティチェックの実施](#run-controls-on-all-branches)。Terraformの検証は1つ目のレイヤと重複するものの、セキュリティスキャナーにより以前にスキャナーが実行されたときにはまだ存在していなかった脅威を見つけられる可能性があります（stagingへのデプロイの数日後にproductionへのデプロイを行う場合など）。\n\n*\n[buildとdeployジョブを上書きして特定のルールを設定](#cd-to-review-environments)。早すぎる削除を防ぐために、`destroy`ステージは自動化されないようになったことにご注意ください。\n\n\n上述のとおり、`TF_STATE_NAME`と`TF_CLI_ARGS_plan`は、[メインパイプライン](#the-main-pipeline)から[子パイプライン](#the-child-pipeline)に渡されています。これらの値を[子パイプライン](#the-child-pipeline)から[孫パイプライン](#the-grand-child-pipeline)に渡すには、別の変数名が必要でした。そのため、子パイプラインでは変数名の末尾に`_2`を付け足し、`before_script`の実行中に適切な変数に値をコピーしています。\n\n\n各ステップについては説明済みであるため、ここでは細かいところは省き、直接グローバルな2つ目のレイヤの定義（`.gitlab-ci/.second-layer.gitlab-ci.yml`に保存）の全体像をご確認ください。\n\n\n```yml\n\n# Use to deploy a second environment on both the default branch and the\ntags.\n\n\ninclude:\n  template: Terraform.gitlab-ci.yml\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n\nfmt:\n  rules:\n    - when: never\n\nvalidate:\n  rules:\n    - when: never\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: always\n\n###########################################################################################################\n\n## QA env. and Prod. env\n\n##  * Manually trigger build and auto-deploy in QA\n\n##  * Manually trigger both build and deploy in Production\n\n##  * Destroy of these env. is not automated to prevent errors.\n\n###########################################################################################################\n\nbuild:  # terraform plan\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment:\n    name: $TF_STATE_NAME_2\n    action: prepare\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - when: manual\n\ndeploy: # terraform apply\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment: \n    name: $TF_STATE_NAME_2\n    action: start\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG && $TF_AUTO_DEPLOY == \"true\"\n    - if: $CI_COMMIT_TAG\n      when: manual\n###########################################################################################################\n\n```\n\n\nこれで**準備完了です。**\n本番環境にデプロイする前に、ジョブの実行を管理する方法は自由に変更できます。たとえば、GitLabの機能を活用して、本番環境へのデプロイ前に[ジョブを遅延させる](https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay)設定をすることも可能です。\n\n\n## 実際に試す\n\n\nついに目標を達成できました。**フィーチャーブランチ**、**mainブランチ**、**タグ**だけで、**5つの異なる環境へのデプロイ**を管理できるようになりました。\n\n* パイプラインの効率とセキュリティを確保するために、GitLabのオープンソーステンプレートを集中的に再利用しました。\n\n* GitLabテンプレートの機能を活用して、個別に制御が必要なブロックだけを上書きしました。\n\n* パイプラインを小さな塊に分割し、ニーズに完全に合うようにダウンストリームパイプラインを制御しました。\n\n\nここからは、自由に進めてください。たとえば、[trigger:rules:changes](https://docs.gitlab.com/ee/ci/yaml/#ruleschanges)キーワードを使って、ソフトウェアのソースコードのダウンストリームパイプラインをトリガーするように、メインパイプラインを簡単に更新することも可能です。また、発生した変更に応じて、別の[テンプレート](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/)を使用できます。その方法はまた別の機会に。\n",[109,680,9,751,681],"2025-06-12",{"slug":816,"featured":6,"template":685},"using-child-pipelines-to-continuously-deploy-to-five-environments","content:ja-jp:blog:using-child-pipelines-to-continuously-deploy-to-five-environments.yml","Using Child Pipelines To Continuously Deploy To Five Environments","ja-jp/blog/using-child-pipelines-to-continuously-deploy-to-five-environments.yml","ja-jp/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"_path":822,"_dir":247,"_draft":6,"_partial":6,"_locale":7,"seo":823,"content":828,"config":837,"_id":839,"_type":14,"title":840,"_source":16,"_file":841,"_stem":842,"_extension":19},"/ja-jp/blog/ci-deployment-and-environments",{"config":824,"ogImage":825,"description":826,"title":827},{"noIndex":6},"https://res.cloudinary.com/about-gitlab-com/image/upload/f_auto,q_auto,c_lfill/v1749662033/Blog/Hero%20Images/intro.jpg","GitLab CI の多様性とパワーをAWS(S3)を例に学び、デプロイに活かせる開発力を身に着けましょう。","GitLab CIを使って複数の環境にデプロイする方法 | GitLab",{"heroImage":825,"body":829,"authors":830,"updatedDate":833,"date":834,"title":835,"tags":836,"description":826,"category":676},"いくつかのシナリオを通じて、[GitLab\n\n\nCI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/)\n\n\nが持つ多様性と強みをご紹介します。\n\n\n\nこの投稿は、ある架空のニュースポータルのサクセスストーリーです。あなたは、そのポータルの所有者かつエディターで、唯一の開発者でもあります。プロジェクトコードは既に GitLab.com でホストされており、GitLab CI/CD で[テストを実行する (英語版)](https://docs.gitlab.com/ee/ci/testing/)こともできます。ここであなたは考えます。これを[デプロイに使う (英語版)](https://about.gitlab.com/blog/2022/02/03/how-to-keep-up-with-ci-cd-best-practices/)ことはできないだろうかと。そして、どこまで活用できるのだろう、と。\n\n\n\nこのサクセスストーリーを技術スタックに依存しないものにするために、このアプリは単なるHTML ファイルを集めたものだと仮定しましょう。サーバー側のコードも、高度な JavaScript のコンパイルもないものとします。\n\n\n\nデプロイ先のプラットフォームも単純なものにしましょう。ここでは、「[Amazon S3](https://aws.amazon.com/jp/s3/)」を使います。\n\n\n\nこの記事の目的は、コピー＆ペースト可能なスニペットを数多く紹介することではありません。[GitLab CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/) の基本原理や各種機能をご紹介し、それを現場の技術スタックに簡単に適用できるようにすることが目的です。\n\n\n\nそれでは、はじめましょう。このストーリーには、まだ、継続的インテグレーション (CI) は登場しません。\n\n\n\n\n\n## 最初のステップ\n\n\n\n**デプロイ**：今回、「デプロイ」とは、一連の HTML ファイルが ([静的な Web サイトホスティング ](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html)用に設定済み) S3 バケット上に表示されることを意味します。\n\n\n\nこれを実現する方法は無数にあります。ここでは、Amazon から提供されている[ awscli ライブラリ (英語版)](http://docs.aws.amazon.com/cli/latest/reference/s3/cp.html#%E4%BE%8B) を使います。\n\n\n\nコマンドは、全体ではこのようになります。\n\n\n\n```shell\n\n\naws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n\n\n```\n\n\n\n![Manual deployment](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/13.jpg){: .center}\n\n\n\nリポジトリへのコードのプッシュと、デプロイは別々のプロセスです。\n\n\n\n{: .note .text-center}\n\n\n\n重要なポイント：このコマンドは、2 つの環境変数`AWS_ACCESS_KEY_ID` と  `AWS_SECRET_ACCESS_KEY` の指定を[コードデベロッパーが行なうものと想定](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence)しています。また、\n\n\n\n重要なポイント：このコマンドは、2 つの環境変数 AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY の指定を[コードデベロッパーが行なうものと想定](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence)しています。また、`AWS_DEFAULT_REGION` も指定する必要があるかもしれません。\n\n\n\nでは、[GitLab CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/) を使って自動化してみましょう。\n\n\n\n\n\n\n## **はじめての自動化デプロイ**\n\n\n\nGitLab では、どのコマンドを実行しても違いはありません。GitLab CI はユーザーの具体的なニーズに合わせて、あたかもコンピュータ上のローカルターミナルで操作している感覚でセットアップできます。ここで実行するコマンドをGitLabにも実行させるよう、CI に指定可能です。 `.gitlab-ci.yml`ファイルにスクリプトを記述し、コードをプッシュするだけです。これで、CI がジョブをトリガーし、指定コマンドが実行されます。\n\n\n\nでは、ここでストーリーにもう少し肉付けをしましょう。私たちの Web サイトは小規模で、1日あたり 20～30 人の訪問者がいるだけです。コードリポジトリには`main` という1つのデフォルトブランチ (があるものとします。\n\n\n\nそれでは、 `.gitlab-ci.yml` ファイルに、先程のコマンドを使った*ジョブ*を指定することから始めましょう。\n\n\n\n```yaml\n\n\ndeploy:\n  script: aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n\n\nうまくいかないようです：\n\n\n\n![Failed command](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/fail1.png){: .shadow}\n\n\n\n実行ファイルには`aws` が必要です。これを確認するのは、私たちの*ジョブ*です。`awscli` をインストールするには、pipが必要です。これは、Pythonパッケージのインストール用のツールです。では、Pythonが事前にインストール済みのDockerイメージを指定しましょう。これには`pip` が含まれているはずです。\n\n\n\n\n\n\n```yaml\n\n\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n\n\n![Automated deployment](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/14.jpg){: .center}\n\n\n\nGitLab にコードをプッシュすると、CI により自動的にデプロイされます。awscli のインストールによりジョブの実行時間が伸びますがこの時点ではそれほど問題ではありません。プロセスを高速化する場合、awscliが事前にインストールされた [Docker イメージを探す (英語版)](https://hub.docker.com/)  ことが可能です。または、イメージをご自身で作成しても構いません。\n\n\n\nここで、[AWS コンソール (英語版) ](https://console.aws.amazon.com/)から取得した環境変数を忘れないでください。\n\n\n\n\n\n\n```yaml\n\n\nvariables:\n  AWS_ACCESS_KEY_ID: \"AKIAIOSFODNN7EXAMPLE\"\n  AWS_SECRET_ACCESS_KEY: \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n\n\n今回は上手くいくはずですが、シークレットキーをオープンにしたままにすることは、プライベートリポジトリであってもよくありません。ではどうすればよいのか、もう少し見てみましょう。\n\n\n\n### **シークレット事項を守り抜くために**\n\n\n\nGitLab にはシークレット変数用に特別な項目があります:  **Settings（設定） > CI/CD > Variables（変数）**\n\n\n\n![Picture of Variables page](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/add-variable-updated.png)\n\n\n\nここに入力したものすべてが**環境変数**になります。「Visibility（表示レベル）」の「Masked（マスクする）」ラジオボタンをオンにすると、ジョブログ内で変数がマスクされます。「Protect variable（変数の保護）」チェックボックスにチェックを入れると、変数は保護されているブランチやタグ上で実行されているパイプラインにのみ、エクスポートされます。プロジェクトの「オーナー」や「メンテナー」の権限を持つユーザーが、このセクションにアクセスできます。\n\n\n\nCI 設定から、variables セクションを削除することも可能ですが、別の目的で使用してみましょう。\n\n\n\n\n\n\n### **シークレットではない変数を指定して使用する方法**\n\n\n\n構成が大きくなる場合、初期段階で、いくつかのパラメータを変数として設定しておくと便利です。これは特に、パラメータを複数の場面で使用する場合に便利です。今回のケースではまだそのような状況ではありませんが、デモとして、S3 バケット名を **[variable](https://docs.gitlab.com/ee/ci/variables/)** に設定してみましょう。\n\n\n\n```yaml\n\n\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n\n\nここまで、順調ですね。\n\n\n\n![Successful build](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/build.png){: .shadow.medium.center}\n\n\n\nこの架空シナリオでは、Web サイトの訪問者数が増えたため、開発者を雇いました。これでチームができました。チームワークにより、[GitLab CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/) ワークフローがどのように変化するのか、見てみましょう。\n\n\n\n\n\n\n## **GitLab CIをチームで使う方法**\n\n\n\n同一のリポジトリで 2 人が作業をするようになったため、開発に main ブランチを使うのは得策ではなくなりました。そこで、新規機能や新規記事ごとに異なるブランチを使うことにし、準備ができたら、main ブランチにマージする、ということに決めました。\n\n\n\nここで問題があります。現行の CI 設定は、ブランチをまったく考慮していない、という点です。GitLab に何かをプッシュするたびに、S3 にデプロイされてしまいます。\n\n\n\nこの問題は簡単に回避できます。deploy するジョブに、only: main を追加するだけです。\n\n\n\n\n\n\n![Automated deployment of main branch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/15-updated.png){: .center}\n\n\n\n本番の Web サイトに、すべてのブランチをデプロイしたくありませんが、フィーチャーブランチからの変更点を何らかの方法でプレビューできたら嬉しいですね。\n\n\n\n\n\n\n{: .note .text-center}\n\n\n\n### **コードのテスト用に別の場所を設定する方法**\n\n\n\n最近雇った人 (ここでは「パトリック」と呼びましょう) が、GitLab には[ GitLab Pages (英語版)](https://about.gitlab.com/stages-devops-lifecycle/pages/) という機能がある、と教えてくれました。作業中のコードをプレビューする場所にもってこいです。\n\n\n\n[GitLab Pagesで Web サイトをホストする (英語版) ](https://about.gitlab.com/blog/2016/04/07/gitlab-pages-setup/) には、CI 設定ファイルが 次の3 つのシンプルなルールを満たしている必要があります。\n\n\n\n* ジョブはpagesと名付けなければならない\n\n\n* artifacts セクションがあり、その中に public フォルダを作成しなければならない\n\n\n* ホストしたいすべてのファイルは、このpublic フォルダ内に置かなければならない\n\n\n\npublic フォルダの中身は、http://\u003Cusername>.gitlab.io/\u003Cprojectname>/でホストされます。\n\n\n\nプレーン[ HTML Web サイト用の設定例](https://gitlab.com/pages/plain-html/blob/master/.gitlab-ci.yml)を適用した後は、CI設定全体はこのようになります。\n\n\n\n\n\n\n```yaml\n\n\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\n\n\n2 つのジョブを指定しました。1つは、顧客用に Web サイトを S3 にデプロイします (deploy)。もう1つのジョブ (pages) は、Web サイトを GitLab Pages にデプロイします。2 つのジョブは、それぞれ「本番環境」と「ステージング環境」と呼びます。\n\n\n\n\n\n\n![Deployment to two places](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/16-updated.png){: .center}\n\n\n\nマスター以外の全ブランチが GitLab Pages にデプロイされます。\n\n\n\n\n\n\n{: .note .text-center}\n\n\n\n## **環境の導入**\n\n\n\nGitLab は[ 環境へのサポート (英語版)](https://docs.gitlab.com/ee/ci/environments/) (動的環境および静的環境を含む) を提供しているため、ユーザーは、各デプロイジョブに対応する環境を指定するだけで済みます。\n\n\n\n```yaml\n\n\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  environment: staging\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\n\n\nGitLab はユーザーのデプロイを追跡するため、サーバー上で何がデプロイされているのかを常に把握できます。\n\n\n\n![List of environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/envs-updated.png){: .shadow.center}\n\n\n\nGitLab は現在の環境のそれぞれについて、デプロイの完全履歴を提供してくれます。\n\n\n\n\n\n\n![List of deployments to staging environment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/staging-env-detail-updated.png){: .shadow.center}\n\n\n\n![Environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/17-updated.png){: .center}\n\n\n\nすべてが自動化され、セットアップも完了です。これで、新しい課題にチャレンジする準備が整いました。\n\n\n\n## **デプロイのトラブルシューティング方法**\n\n\n\nまた、同じことが起きました。ステージング環境で自分のフィーチャーブランチをプレビューするためにプッシュした 1 分後、パトリックが彼のブランチをプッシュしたのです。ステージング環境はパトリックの作業内容で上書きされてしまいました。大変です。今日で 3 回目です。\n\n\n\nそこで、アイデアが浮かびました。Slackを使ってデプロイを通知するようにすれば、デプロイが完了した時に、コンテンツを別の人がプッシュしてしまうことがなくなります。\n\n\n\n\n\n\n> [GitLabとSlackを連携する方法はこちら](https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html)\n\n\n\n## **規模に応じたチームワーク**\n\n\n\n時は過ぎ、Web サイトの人気は非常に上がり、チームも 2 人から 8 人に増えました。チームメンバーは同時進行で開発を行うため、「ステージング」でプレビューを待ち合うことが多くなってきました。「ステージングに対してすべてのブランチをデプロイする」という方針はうまくいかなくなってしまったのです。\n\n\n\n\n\n\n![Queue of branches for review on Staging](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/queue.jpg){: .center}\n\n\n\nもう一度、プロセスを見直す時がきました。誰かがステージングサーバー上でコードへの変更内容を確認したいときは、まず「ステージング」ブランチに変更内容をマージする、ということにチームで同意しました。\n\n\n\n.gitlab-ci.yml への変更は最小限に抑えられます。\n\n\n\n```yaml\n\n\nexcept:\n\n\n\n- main\n\n\n```\n\n\n\nを次のように変更します：\n\n\n\n```yaml\n\n\nonly:\n\n\n\n- staging\n\n\n```\n\n\n\n![Staging branch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/18-updated.png){: .center}\n\n\n\nステージングサーバー上でプレビューを行なう前に、フィーチャーブランチをマージしなければなりません。\n\n\n\n{: .note .text-center}\n\n\n\nもちろん、これによりマージに追加の時間や労力がかかりますが、待機するよりは良い、ということで全員が同意しました。\n\n\n\n### **緊急時の対応**\n\n\n\nすべてを制御することは不可能です。そのため、時として何かがうまくいかないこともあります。誰かがブランチを誤った方法でマージしてしまい、あなたのサイトが HackerNews のトップに載ったタイミングで、本番環境に直接プッシュしてしまいました。何千人もの人が、輝かしいメインページの代わりに、完全に崩れたレイアウトを目撃してしまったのです。\n\n\n\nしかし幸運なことに、「**ロールバック**」ボタンを見つけた人がいたため、問題発覚 1 分後に、Web サイトは修正されました。\n\n\n\n\n\n\n![List of environments](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/prod-env-rollback-arrow-updated.png){: .shadow.center}\n\n\n\n「ロールバック」により、1つ前のコミットでの1つ前のジョブが再起動されます\n\n\n\n\n\n\n{: .note .text-center}\n\n\n\nとにかく、この問題に対応する必要があると感じたため、本番環境への GitLab 自動デプロイを停止して、手動デプロイに切り替えることにしました。そのためには、ジョブに when: manual を追加する必要があります。\n\n\n\n予想通り、その後は「本番環境」への自動デプロイは行なわれなくなりました。手動でデプロイするには、**CI/CD > Pipelines（パイプライン）** に移動し、下図にあるボタンをクリックします。\n\n\n\n\n\n\n![Skipped job is available for manual launch](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/manual-pipeline-arrow-updated.png){: .shadow.center}\n\n\n\n時間を早送りしましょう。ついに、あなたの組織は法人化されました。Web サイトに取り組んでいる人も数百人になり、これまでの妥協策はもう通用しません。\n\n\n\n### **「Review Apps」の出番です**\n\n\n\n次にすべき論理的なステップは、レビュー用に、フィーチャーブランチごとにアプリケーションの一時インスタンスを起動することでしょう。\n\n\n\nここでは、そのために S3 上に別のバケットをセットアップします。ただ一つ違うところは、開発ブランチの名前で Web サイトのコンテンツを「フォルダ」にコピーする点です。URL は次のようになります。\n\n\n\nhttp://\u003CREVIEW_S3_BUCKET_NAME>.s3-website-us-east-1.amazonaws.com/\u003Cbranchname>/\n\n\n\n前に使った pages ジョブを次のコードで置き換えます。\n\n\n\n\n\n\n```yaml\n\n\nreview apps:\n  variables:\n    S3_BUCKET_NAME: \"reviewbucket\"\n  image: python:latest\n  environment: review\n  script:\n  - pip install awscli\n  - mkdir -p ./$CI_BUILD_REF_NAME\n  - cp ./*.html ./$CI_BUILD_REF_NAME/\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n\n\n興味深いのは、$CI_BUILD_REF_NAME という変数がどこからきたか、という点です。GitLab は [多くの環境変数 (英語版)](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) があらかじめ定義されています。そのため、ジョブではすぐ変数が使えます。\n\n\n\nここでご注意いただきたいのは、S3_BUCKET_NAME 変数はジョブ内で定義している、ということです。トップレベルの定義を再定義するとき、これを行ないます。\n\n\n\n\n\n\n\n\n{: .alert .alert-info}\n\n\n\nこの構成を視覚的にわかりやすく描くと、次のようになります。\n\n\n\n\n\n![How to use GitLab CI - update - 19 - updated](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/19-updated.png){: .illustration}\n\n\n\n\n\n「Review Apps」の実装の詳細は、実際に現場で使っている技術スタックやデプロイプロセスなどにより大きく異なります。そのため、このブログ記事では詳細をカバーできません。\n\n\n\n現実は、この静的な HTML Web サイトのように簡単ではないのです。例えば、あるインスタンスを一時インスタンスにして、必要なソフトウェアやサービスを即座に、自動的に起動させることは簡単な作業ではありません。しかし、特に Docker コンテナ、または Chef や Ansible を使えば実現可能です。\n\n\n\nDocker を使ったデプロイについては、今後のブログ記事で取り上げます。GitLab デプロイプロセスをシンプルな HTML ファイルのコピーに単純化し、より複雑なシナリオにしなかったことに対して、少々後めたい気持ちがあります。複雑なシナリオを知りたい方は、「Building an Elixir Release into a Docker image using GitLab CI (英語版のみ：[GitLab CI を使用して、Elixir リリースを Docker イメージにビルドする)」 をご覧ください](https://about.gitlab.com/blog/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/)。\n\n\n\nさて、記事に戻ります。最後の点について、お話しましょう。\n\n\n\n\n\n\n### **異なるプラットフォームへの GitLab デプロイ**\n\n\n\n現実は、S3 や GitLab Pages だけに限定されるものではありません。GitLab はまざまなサービスにアプリやパッケージをホストし、デプロイしています。\n\n\n\nさらに、ある時点で、新しいプラットフォームへの移行を決定し、デプロイスクリプトをすべて書き直す必要が生じるかもしれません。そういった場合のダメージを最小限に抑えるために、dpl という Gem を使えます。\n\n\n\n上の例では、サービス (Amazon S3) へのコードのサンプルツールとして awscli を使用しました。しかし、どのツールを使っても、また、デプロイ先のシステムに何を選んでも、基本原則は変わりません。いくつかのパラメータでコマンドを実行し、何らかの方法で認証用にシークレットキーを渡すということです。\n\n\n\ndpl のデプロイツールは、この基本原則に従い、[このプロバイダーのリスト](https://github.com/travis-ci/dpl#supported-providers)に対して統一されたインターフェイスを提供します。\n\n\n\nこちらが、dplを使用した場合の、本番デプロイジョブの例です。\n\n\n\n\n\n```yaml\n\n\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: ruby:latest\n  script:\n  - gem install dpl\n  - dpl --provider=s3 --bucket=$S3_BUCKET_NAME\n  only:\n  - main\n```\n\n\n\n異なるシステムにデプロイする場合、またはデプロイ先のプラットフォームを頻繁に変更する場合には、デプロイ用スクリプトが統一されるように dplを使うことを検討してください。\n\n\n\n\n\n\n## **まとめ：5つの重要なポイント**\n\n\n\nGitLab での CI デプロイについて、CI/CD AWS を使って説明してきました。GitLab AWS デプロイについて役立つ知識が得られたでしょうか。これまで学んできたポイントをまとめると、次のようになります。\n\n\n\n1. デプロイとは、定期的に実行される、単一の (もしくは一連の) コマンドにすぎません。このため、デプロイは [GitLab CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/) 内で実行できます。\n\n\n2. ほとんどの場合、実行するコマンドに対していくつかの (もしくは単一の) シークレットキーを指定する必要があります。指定するシークレットキーは、**Settings （設定）> CI/CD > Variables（変数）** に格納します。\n\n\n3. [GitLab CI](https://about.gitlab.com/ja-jp/solutions/continuous-integration/) では、デプロイ先のブランチを柔軟に指定できます。\n\n\n4. 複数の環境にデプロイする場合、GitLab はデプロイ履歴を保持します。そのため、任意の前バージョンにロールバックできます。\n\n\n5. インフラストラクチャの重要な部分については、GitLab 自動デプロイの代わりに、GitLab インターフェイスからの手動デプロイを有効化できます。\n\n\n\n\u003Cstyle>\n\n\n\nimg.illustration {\n  padding-left: 12%;\n  padding-right: 12%;\n\n}\n\n\n\n@media (max-width: 760px) {\n  img.illustration {\n    padding-left: 0px;\n    padding-right: 0px;\n  }\n}\n\n\n\n\u003C/style>\n\n\n\n*監修：小松原 つかさ [@tkomatsubara](https://gitlab.com/tkomatsubara)*\n\n\n\n*（GitLab合同会社 ソリューションアーキテクト本部 シニアパートナーソリューションアーキテクト）*\n",[831,832],"Ivan Nemytchenko","Cesar Saavedra","2025-08-22","2021-02-05","GitLab CIを使って複数の環境にデプロイする方法",[680,9,681],{"featured":6,"template":685,"slug":838},"ci-deployment-and-environments","content:ja-jp:blog:ci-deployment-and-environments.yml","Ci Deployment And Environments","ja-jp/blog/ci-deployment-and-environments.yml","ja-jp/blog/ci-deployment-and-environments",1,[661,690,714,737,758,777,800],1758662385717]