{"id":2356,"date":"2025-03-24T08:47:36","date_gmt":"2025-03-23T23:47:36","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=2356"},"modified":"2025-03-24T08:47:59","modified_gmt":"2025-03-23T23:47:59","slug":"%e3%80%90%e4%bf%9d%e5%ae%88%e6%80%a7%e6%8a%9c%e7%be%a4%e3%80%91terraform-templatefile%e3%81%ae%e5%ae%9f%e8%b7%b5%e7%9a%84%e3%81%aa%e4%bd%bf%e3%81%84%e6%96%b97%e9%81%b8-%e3%80%9c-%e9%81%8b%e7%94%a8","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=2356","title":{"rendered":"\u3010\u4fdd\u5b88\u6027\u629c\u7fa4\u3011Terraform templatefile\u306e\u5b9f\u8df5\u7684\u306a\u4f7f\u3044\u65b97\u9078 \u301c \u904b\u7528\u52b9\u7387\u30923\u500d\u306b\u3059\u308b\u6226\u7565\u30c6\u30af\u30cb\u30c3\u30af"},"content":{"rendered":"\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">templatefile\u95a2\u6570\u3068\u306f\uff1fDRY\u306a\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u3092\u5b9f\u73fe\u3059\u308b\u5f37\u529b\u306a\u6a5f\u80fd<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">templatefile\u95a2\u6570\u306e\u57fa\u672c\u7684\u306a\u69cb\u6587\u3068\u52d5\u4f5c\u539f\u7406<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-2\">\u5f93\u6765\u306e\u5b9f\u88c5\u65b9\u6cd5\u3068\u6bd4\u8f03\u3057\u305f\u969b\u306e\u30e1\u30ea\u30c3\u30c8<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-3\">templatefile\u95a2\u6570\u306e\u5b9f\u8df5\u7684\u306a\u4f7f\u7528\u4f8b7\u9078<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-4\">EC2\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5\u30b9\u30af\u30ea\u30d7\u30c8\u81ea\u52d5\u751f\u6210<\/a>      <\/li>      <li>        <a href=\"#i-5\">\u8907\u6570\u74b0\u5883\u5411\u3051IAM\u30dd\u30ea\u30b7\u30fc\u7ba1\u7406<\/a>      <\/li>      <li>        <a href=\"#i-6\">\u52d5\u7684\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30b0\u30eb\u30fc\u30d7\u30eb\u30fc\u30eb\u306e\u8a2d\u5b9a<\/a>      <\/li>      <li>        <a href=\"#i-7\">\u74b0\u5883\u5909\u6570\u3092\u6d3b\u7528\u3057\u305fRDS\u8a2d\u5b9a\u306e\u7ba1\u7406<\/a>      <\/li>      <li>        <a href=\"#i-8\">ECS\u30bf\u30b9\u30af\u5b9a\u7fa9\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5316<\/a>      <\/li>      <li>        <a href=\"#i-9\">\u30de\u30eb\u30c1\u30ea\u30fc\u30b8\u30e7\u30f3\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u306e\u8a2d\u5b9a<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-10\">\u30ab\u30b9\u30bf\u30e0\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u8a2d\u5b9a\u306e\u52d5\u7684\u751f\u6210<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-11\">templatefile\u95a2\u6570\u4f7f\u7528\u6642\u306e\u5b9f\u88c5\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-12\">\u5909\u6570\u306e\u30b9\u30b3\u30fc\u30d7\u3068\u547d\u540d\u898f\u5247\u306e\u7d71\u4e00<\/a>      <\/li>      <li>        <a href=\"#i-13\">\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u3068\u578b\u5b89\u5168\u6027\u306e\u78ba\u4fdd<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-14\">\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u69cb\u9020\u5316\u3068\u7ba1\u7406\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-15\">\u904b\u7528\u52b9\u7387\u3092\u9ad8\u3081\u308btemplatefile\u6d3b\u7528\u8853<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-16\">\u30c6\u30b9\u30c8\u3068\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u81ea\u52d5\u5316\u624b\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-17\">\u30c1\u30fc\u30e0\u958b\u767a\u306b\u304a\u3051\u308b\u6a19\u6e96\u5316\u30a2\u30d7\u30ed\u30fc\u30c1<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-18\">\u65e2\u5b58\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u306e\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u6226\u7565<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-19\">\u3088\u304f\u3042\u308b\u30a8\u30e9\u30fc\u3068\u89e3\u6c7a\u65b9\u6cd5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-20\">\u69cb\u6587\u30a8\u30e9\u30fc\u306e\u4e3b\u306a\u539f\u56e0\u3068\u5bfe\u51e6\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-21\">\u5909\u6570\u53c2\u7167\u306b\u95a2\u3059\u308b\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-22\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30d2\u30f3\u30c8<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-23\">\u5fdc\u7528\uff1a\u5927\u898f\u6a21\u30b7\u30b9\u30c6\u30e0\u306b\u304a\u3051\u308btemplatefile\u6d3b\u7528\u4e8b\u4f8b<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-24\">\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u3067\u306e\u30de\u30eb\u30c1\u6d3b\u7528\u4f8b<\/a>      <\/li>      <li>        <a href=\"#i-25\">\u30a2\u30ab\u30a6\u30f3\u30c8\u6226\u7565\u3067\u306e\u5b9f\u73fe\u30d1\u30bf\u30fc\u30f3<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-26\">\u7d99\u7d9a\u7684\u306a\u30c7\u30ea\u30d0\u30ea\u30fc\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u3067\u306e\u7d71\u5408\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">templatefile\u95a2\u6570\u3068\u306f\uff1fDRY\u306a\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u3092\u5b9f\u73fe\u3059\u308b\u5f37\u529b\u306a\u6a5f\u80fd<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-1\">templatefile\u95a2\u6570\u306e\u57fa\u672c\u7684\u306a\u69cb\u6587\u3068\u52d5\u4f5c\u539f\u7406<\/h3>\n\n\n\n<p>Terraform \u306e <code>templatefile<\/code> \u95a2\u6570\u306f\u3001\u5916\u90e8\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u3001\u5909\u6570\u7f6e\u63db\u3092\u884c\u3046\u3053\u3068\u3067\u52d5\u7684\u306a\u30b3\u30f3\u30d5\u30a3\u30ae\u30e5\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u751f\u6210\u3059\u308b\u5f37\u529b\u306a\u6a5f\u80fd\u3067\u3059\u3002\u3053\u306e\u95a2\u6570\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u30a4\u30f3\u30d5\u30e9\u30b9\u30c8\u30e9\u30af\u30c1\u30e3\u30b3\u30fc\u30c9\u306e\u518d\u5229\u7528\u6027\u3068\u4fdd\u5b88\u6027\u3092\u5927\u5e45\u306b\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u57fa\u672c\u7684\u306a\u69cb\u6587\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">templatefile(path, vars)<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>path<\/code>: \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3078\u306e\u30d1\u30b9\uff08\u6587\u5b57\u5217\uff09<\/li>\n\n\n\n<li><code>vars<\/code>: \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5185\u3067\u4f7f\u7528\u3059\u308b\u5909\u6570\u306e\u30de\u30c3\u30d7<\/li>\n<\/ul>\n\n\n\n<p>\u5b9f\u969b\u306e\u4f7f\u7528\u4f8b\u3092\u898b\u3066\u307f\u307e\u3057\u3087\u3046\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_instance\" \"web\" {\n  ami           = \"ami-0c55b159cbfafe1f0\"\n  instance_type = \"t2.micro\"\n\n  user_data = templatefile(\"${path.module}\/scripts\/init.sh.tpl\", {\n    environment = var.environment\n    region      = var.aws_region\n    db_host     = aws_db_instance.main.endpoint\n  })\n}\n\n# scripts\/init.sh.tpl\n#!\/bin\/bash\necho \"Starting initialization for ${environment} environment in ${region}\"\ncat &lt;&lt; EOF &gt; \/etc\/application.conf\nDATABASE_URL=postgresql:\/\/${db_host}:5432\/myapp\nENVIRONMENT=${environment}\nEOF<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-2\">\u5f93\u6765\u306e\u5b9f\u88c5\u65b9\u6cd5\u3068\u6bd4\u8f03\u3057\u305f\u969b\u306e\u30e1\u30ea\u30c3\u30c8<\/h3>\n\n\n\n<p>\u5f93\u6765\u306e\u5b9f\u88c5\u65b9\u6cd5\u3068 templatefile \u95a2\u6570\u3092\u4f7f\u7528\u3057\u305f\u5b9f\u88c5\u3092\u6bd4\u8f03\u3057\u3066\u307f\u307e\u3057\u3087\u3046\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5f93\u6765\u306e\u5b9f\u88c5\u65b9\u6cd5<\/strong>:<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u76f4\u63a5\u30ea\u30bd\u30fc\u30b9\u5185\u306b\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u8a18\u8ff0\nresource \"aws_instance\" \"web\" {\n  user_data = &lt;&lt;-EOF\n    #!\/bin\/bash\n    echo \"Starting initialization\"\n    cat &lt;&lt; EOF &gt; \/etc\/application.conf\n    DATABASE_URL=postgresql:\/\/${aws_db_instance.main.endpoint}:5432\/myapp\n    ENVIRONMENT=${var.environment}\n    EOF\n  EOF\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>templatefile\u95a2\u6570\u3092\u4f7f\u7528\u3057\u305f\u5b9f\u88c5<\/strong>:<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u3088\u308a\u6574\u7406\u3055\u308c\u305f\u5b9f\u88c5\nresource \"aws_instance\" \"web\" {\n  user_data = templatefile(\"${path.module}\/scripts\/init.sh.tpl\", {\n    db_host     = aws_db_instance.main.endpoint\n    environment = var.environment\n  })\n}<\/pre>\n\n\n\n<p>templatefile\u95a2\u6570\u3092\u4f7f\u7528\u3059\u308b\u4e3b\u306a\u30e1\u30ea\u30c3\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30b3\u30fc\u30c9\u306e\u518d\u5229\u7528\u6027<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u8907\u6570\u306e\u30ea\u30bd\u30fc\u30b9\u3067\u5171\u6709\u53ef\u80fd<\/li>\n\n\n\n<li>\u74b0\u5883\u3084\u30ea\u30fc\u30b8\u30e7\u30f3\u3054\u3068\u306e\u8a2d\u5b9a\u3092\u5bb9\u6613\u306b\u7ba1\u7406<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30ed\u30b8\u30c3\u30af\u3068\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u5206\u96e2<\/li>\n\n\n\n<li>\u30d0\u30fc\u30b8\u30e7\u30f3\u7ba1\u7406\u304c\u5bb9\u6613<\/li>\n\n\n\n<li>\u30c1\u30fc\u30e0\u958b\u767a\u3067\u306e\u5909\u66f4\u8ffd\u8de1\u304c\u7c21\u5358<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u53ef\u8aad\u6027\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8907\u96d1\u306a\u30b9\u30af\u30ea\u30d7\u30c8\u3084\u8a2d\u5b9a\u3092\u5225\u30d5\u30a1\u30a4\u30eb\u3067\u7ba1\u7406<\/li>\n\n\n\n<li>\u30e1\u30a4\u30f3\u306eTerraform\u30b3\u30fc\u30c9\u304c\u3059\u3063\u304d\u308a<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30a8\u30e9\u30fc\u691c\u51fa\u306e\u5bb9\u6613\u3055<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u69cb\u6587\u306e\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3<\/li>\n\n\n\n<li>\u5909\u6570\u306e\u578b\u30c1\u30a7\u30c3\u30af<\/li>\n\n\n\n<li>\u672a\u5b9a\u7fa9\u5909\u6570\u306e\u65e9\u671f\u767a\u898b<\/li>\n<\/ul>\n\n\n\n<p>\u9ad8\u5ea6\u306a\u4f7f\u7528\u4f8b\uff1a\u6761\u4ef6\u5206\u5c90\u3068\u30eb\u30fc\u30d7\u306e\u6d3b\u7528<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config.json.tpl\n{\n  \"environment\": \"${environment}\",\n  \"services\": [\n    %{ for service in services ~}\n    {\n      \"name\": \"${service.name}\",\n      \"port\": ${service.port},\n      \"enabled\": ${service.enabled ? \"true\" : \"false\"}\n    }%{ if !is_last(service) ~},\n    %{ endif ~}\n    %{ endfor ~}\n  ]\n}<\/pre>\n\n\n\n<p>\u3053\u306e\u3088\u3046\u306a\u9ad8\u5ea6\u306a\u6a5f\u80fd\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u3088\u308a\u67d4\u8edf\u3067\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u30a4\u30f3\u30d5\u30e9\u30b9\u30c8\u30e9\u30af\u30c1\u30e3\u30b3\u30fc\u30c9\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-3\">templatefile\u95a2\u6570\u306e\u5b9f\u8df5\u7684\u306a\u4f7f\u7528\u4f8b7\u9078<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-4\">EC2\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5\u30b9\u30af\u30ea\u30d7\u30c8\u81ea\u52d5\u751f\u6210<\/h3>\n\n\n\n<p>EC2\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5\u6642\u306b\u5fc5\u8981\u306a\u8a2d\u5b9a\u3092\u52d5\u7684\u306b\u751f\u6210\u3059\u308b\u4f8b\u3067\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_instance\" \"application\" {\n  ami           = var.ami_id\n  instance_type = var.instance_type\n\n  user_data = templatefile(\"${path.module}\/templates\/user_data.sh.tpl\", {\n    app_name    = var.application_name\n    environment = var.environment\n    region      = var.aws_region\n    log_level   = var.environment == \"prod\" ? \"ERROR\" : \"DEBUG\"\n    env_vars    = var.environment_variables\n  })\n}\n\n# templates\/user_data.sh.tpl\n#!\/bin\/bash\n# \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u521d\u671f\u8a2d\u5b9a\u30b9\u30af\u30ea\u30d7\u30c8\necho \"Starting ${app_name} in ${environment} environment\"\n\n# \u74b0\u5883\u5909\u6570\u306e\u8a2d\u5b9a\n%{ for key, value in env_vars ~}\nexport ${key}=\"${value}\"\n%{ endfor ~}\n\n# \u30ed\u30ae\u30f3\u30b0\u8a2d\u5b9a\ncat &lt;&lt; EOF &gt; \/etc\/cloudwatch-agent.json\n{\n  \"agent\": {\n    \"region\": \"${region}\",\n    \"logLevel\": \"${log_level}\"\n  }\n}\nEOF<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">\u8907\u6570\u74b0\u5883\u5411\u3051IAM\u30dd\u30ea\u30b7\u30fc\u7ba1\u7406<\/h3>\n\n\n\n<p>\u74b0\u5883\u3054\u3068\u306b\u7570\u306a\u308bIAM\u30dd\u30ea\u30b7\u30fc\u3092\u751f\u6210\u3059\u308b\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_iam_role_policy\" \"service_policy\" {\n  name = \"${var.environment}-service-policy\"\n  role = aws_iam_role.service_role.id\n\n  policy = templatefile(\"${path.module}\/templates\/service_policy.json.tpl\", {\n    environment = var.environment\n    account_id  = data.aws_caller_identity.current.account_id\n    resources   = var.allowed_resources\n    actions     = local.allowed_actions[var.environment]\n  })\n}\n\n# templates\/service_policy.json.tpl\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        %{ for action in actions ~}\n        \"${action}\"%{ if !is_last(action) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"Resource\": [\n        %{ for resource in resources ~}\n        \"arn:aws:s3:::${resource}\/*\"%{ if !is_last(resource) ~},%{ endif ~}\n        %{ endfor ~}\n      ]\n    }\n  ]\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-6\">\u52d5\u7684\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30b0\u30eb\u30fc\u30d7\u30eb\u30fc\u30eb\u306e\u8a2d\u5b9a<\/h3>\n\n\n\n<p>\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u8981\u4ef6\u306b\u5fdc\u3058\u3066\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30b0\u30eb\u30fc\u30d7\u30eb\u30fc\u30eb\u3092\u52d5\u7684\u306b\u751f\u6210\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_security_group\" \"application\" {\n  name_prefix = \"${var.app_name}-sg\"\n  vpc_id      = var.vpc_id\n\n  dynamic \"ingress\" {\n    for_each = jsondecode(templatefile(\"${path.module}\/templates\/security_rules.json.tpl\", {\n      environment = var.environment\n      ports       = var.service_ports\n      cidrs       = var.allowed_cidrs\n    }))\n    content {\n      from_port   = ingress.value.port\n      to_port     = ingress.value.port\n      protocol    = \"tcp\"\n      cidr_blocks = ingress.value.cidrs\n    }\n  }\n}\n\n# templates\/security_rules.json.tpl\n[\n  %{ for port in ports ~}\n  {\n    \"port\": ${port},\n    \"cidrs\": [\n      %{ for cidr in cidrs ~}\n      \"${cidr}\"%{ if !is_last(cidr) ~},%{ endif ~}\n      %{ endfor ~}\n    ]\n  }%{ if !is_last(port) ~},%{ endif ~}\n  %{ endfor ~}\n]<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-7\">\u74b0\u5883\u5909\u6570\u3092\u6d3b\u7528\u3057\u305fRDS\u8a2d\u5b9a\u306e\u7ba1\u7406<\/h3>\n\n\n\n<p>\u74b0\u5883\u3054\u3068\u306eRDS\u8a2d\u5b9a\u3092\u52b9\u7387\u7684\u306b\u7ba1\u7406\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_db_instance\" \"database\" {\n  identifier = var.db_identifier\n\n  engine         = \"postgres\"\n  engine_version = var.engine_version\n\n  allocated_storage = var.allocated_storage\n  instance_class    = var.instance_class\n\n  db_name  = var.database_name\n  username = var.master_username\n  password = var.master_password\n\n  parameter_group_name = aws_db_parameter_group.custom.name\n}\n\nresource \"aws_db_parameter_group\" \"custom\" {\n  name_prefix = \"${var.environment}-db-params\"\n  family      = \"postgres13\"\n\n  parameter {\n    name  = \"shared_preload_libraries\"\n    value = templatefile(\"${path.module}\/templates\/db_params.tpl\", {\n      extensions = var.postgres_extensions\n      environment = var.environment\n    })\n  }\n}\n\n# templates\/db_params.tpl\n%{ for ext in extensions ~}\n'${ext}'%{ if !is_last(ext) ~},%{ endif ~}\n%{ endfor ~}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-8\">ECS\u30bf\u30b9\u30af\u5b9a\u7fa9\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5316<\/h3>\n\n\n\n<p>\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u306eECS\u30bf\u30b9\u30af\u5b9a\u7fa9\u3092\u52d5\u7684\u306b\u751f\u6210\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nresource \"aws_ecs_task_definition\" \"service\" {\n  family                   = \"${var.service_name}-task\"\n  requires_compatibilities = [\"FARGATE\"]\n  network_mode            = \"awsvpc\"\n  cpu                     = var.cpu\n  memory                  = var.memory\n\n  container_definitions = templatefile(\"${path.module}\/templates\/container_definition.json.tpl\", {\n    name           = var.service_name\n    image         = \"${var.ecr_repository_url}:${var.image_tag}\"\n    cpu           = var.cpu\n    memory        = var.memory\n    environment   = var.environment\n    secrets       = var.secrets\n    port_mappings = var.port_mappings\n  })\n}\n\n# templates\/container_definition.json.tpl\n[\n  {\n    \"name\": \"${name}\",\n    \"image\": \"${image}\",\n    \"cpu\": ${cpu},\n    \"memory\": ${memory},\n    \"essential\": true,\n    \"portMappings\": [\n      %{ for mapping in port_mappings ~}\n      {\n        \"containerPort\": ${mapping.container_port},\n        \"hostPort\": ${mapping.host_port},\n        \"protocol\": \"${mapping.protocol}\"\n      }%{ if !is_last(mapping) ~},%{ endif ~}\n      %{ endfor ~}\n    ],\n    \"environment\": [\n      %{ for key, value in environment ~}\n      {\n        \"name\": \"${key}\",\n        \"value\": \"${value}\"\n      }%{ if !is_last(key) ~},%{ endif ~}\n      %{ endfor ~}\n    ],\n    \"secrets\": [\n      %{ for secret in secrets ~}\n      {\n        \"name\": \"${secret.name}\",\n        \"valueFrom\": \"${secret.arn}\"\n      }%{ if !is_last(secret) ~},%{ endif ~}\n      %{ endfor ~}\n    ]\n  }\n]<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">\u30de\u30eb\u30c1\u30ea\u30fc\u30b8\u30e7\u30f3\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u306e\u8a2d\u5b9a<\/h3>\n\n\n\n<p>\u8907\u6570\u30ea\u30fc\u30b8\u30e7\u30f3\u3078\u306e\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u8a2d\u5b9a\u3092\u7ba1\u7406\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># main.tf\nlocals {\n  region_configs = jsondecode(templatefile(\"${path.module}\/templates\/region_config.json.tpl\", {\n    primary_region   = var.primary_region\n    backup_regions   = var.backup_regions\n    environment     = var.environment\n    service_config  = var.service_configuration\n  }))\n}\n\n# templates\/region_config.json.tpl\n{\n  \"primary\": {\n    \"region\": \"${primary_region}\",\n    \"config\": {\n      \"instance_type\": \"${service_config.instance_type}\",\n      \"min_size\": ${service_config.min_size},\n      \"max_size\": ${service_config.max_size},\n      \"environment\": \"${environment}\"\n    }\n  },\n  \"backup\": [\n    %{ for region in backup_regions ~}\n    {\n      \"region\": \"${region}\",\n      \"config\": {\n        \"instance_type\": \"${service_config.dr_instance_type}\",\n        \"min_size\": ${service_config.dr_min_size},\n        \"max_size\": ${service_config.dr_max_size},\n        \"environment\": \"${environment}-dr\"\n      }\n    }%{ if !is_last(region) ~},%{ endif ~}\n    %{ endfor ~}\n  ]\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-10\">\u30ab\u30b9\u30bf\u30e0\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u8a2d\u5b9a\u306e\u52d5\u7684\u751f\u6210<\/h3>\n\n\n\n<p>\u74b0\u5883\u3084\u30ea\u30fc\u30b8\u30e7\u30f3\u306b\u5fdc\u3058\u305f\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u8a2d\u5b9a\u3092\u52d5\u7684\u306b\u751f\u6210\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># backend.tf\nterraform {\n  backend \"s3\" {\n    key = templatefile(\"${path.module}\/templates\/backend_key.tpl\", {\n      environment = var.environment\n      component   = var.component_name\n      region     = var.aws_region\n    })\n  }\n}\n\n# templates\/backend_key.tpl\nterraform\/${environment}\/${region}\/${component}\/terraform.tfstate<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u8df5\u7684\u306a\u4f7f\u7528\u4f8b\u306f\u3001\u5b9f\u969b\u306e\u904b\u7528\u30b7\u30fc\u30f3\u3067\u983b\u7e41\u306b\u906d\u9047\u3059\u308b\u8ab2\u984c\u306b\u5bfe\u3059\u308b\u89e3\u6c7a\u7b56\u3092\u63d0\u4f9b\u3057\u307e\u3059\u3002\u5404\u4f8b\u306f\u5fc5\u8981\u306b\u5fdc\u3058\u3066\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3057\u3066\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-11\">templatefile\u95a2\u6570\u4f7f\u7528\u6642\u306e\u5b9f\u88c5\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-12\">\u5909\u6570\u306e\u30b9\u30b3\u30fc\u30d7\u3068\u547d\u540d\u898f\u5247\u306e\u7d71\u4e00<\/h3>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3067\u4f7f\u7528\u3059\u308b\u5909\u6570\u306e\u7ba1\u7406\u3068\u547d\u540d\u898f\u5247\u306b\u3064\u3044\u3066\u3001\u4ee5\u4e0b\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u7d39\u4ecb\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u63a8\u5968\u3055\u308c\u308b\u5909\u6570\u5b9a\u7fa9\u306e\u65b9\u6cd5\n# variables.tf\nvariable \"environment\" {\n  description = \"\u74b0\u5883\u540d\uff08dev\/stg\/prod\uff09\"\n  type        = string\n  validation {\n    condition     = contains([\"dev\", \"stg\", \"prod\"], var.environment)\n    error_message = \"\u74b0\u5883\u540d\u306fdev\u3001stg\u3001prod\u306e\u3044\u305a\u308c\u304b\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\"\n  }\n}\n\nvariable \"service_config\" {\n  description = \"\u30b5\u30fc\u30d3\u30b9\u306e\u8a2d\u5b9a\"\n  type = object({\n    name          = string\n    instance_type = string\n    min_size      = number\n    max_size      = number\n  })\n}\n\n# locals.tf\nlocals {\n  # \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3067\u4f7f\u7528\u3059\u308b\u5171\u901a\u5909\u6570\u306e\u6a19\u6e96\u5316\n  common_tags = {\n    Environment = var.environment\n    Project     = var.project_name\n    ManagedBy   = \"terraform\"\n  }\n\n  # \u74b0\u5883\u3054\u3068\u306e\u8a2d\u5b9a\u5024\u306e\u30de\u30c3\u30d4\u30f3\u30b0\n  environment_configs = {\n    dev  = { log_level = \"DEBUG\", backup_retention = 7 }\n    stg  = { log_level = \"INFO\",  backup_retention = 14 }\n    prod = { log_level = \"WARN\",  backup_retention = 30 }\n  }\n}<\/pre>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3067\u306e\u4f7f\u7528\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># templates\/app_config.json.tpl\n{\n  \"application\": {\n    \"name\": \"${service_config.name}\",\n    \"environment\": \"${environment}\",\n    \"logLevel\": \"${local.environment_configs[environment].log_level}\",\n    \"tags\": {\n      %{ for key, value in common_tags ~}\n      \"${key}\": \"${value}\"%{ if !is_last(key) ~},%{ endif ~}\n      %{ endfor ~}\n    }\n  }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u3068\u578b\u5b89\u5168\u6027\u306e\u78ba\u4fdd<\/h3>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3067\u306e\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u3068\u578b\u5b89\u5168\u6027\u3092\u78ba\u4fdd\u3059\u308b\u305f\u3081\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u578b\u5b89\u5168\u6027\u3092\u78ba\u4fdd\u3057\u305f\u5909\u6570\u5b9a\u7fa9\nvariable \"port_mappings\" {\n  description = \"\u30b3\u30f3\u30c6\u30ca\u306e\u30dd\u30fc\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\"\n  type = list(object({\n    container_port = number\n    host_port      = number\n    protocol       = string\n  }))\n\n  validation {\n    condition     = alltrue([for p in var.port_mappings : contains([\"tcp\", \"udp\"], p.protocol)])\n    error_message = \"\u30d7\u30ed\u30c8\u30b3\u30eb\u306ftcp\u307e\u305f\u306fudp\u3067\u3042\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\"\n  }\n}\n\n# \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u3092\u542b\u3080\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\n# templates\/container_config.json.tpl\n{\n  \"containerDefinitions\": [\n    {\n      \"portMappings\": [\n        %{ for mapping in port_mappings ~}\n        {\n          %{ if mapping.container_port == null ~}\n          ${format(\"Container port cannot be null for %s\", mapping)}\n          %{ endif ~}\n          \"containerPort\": ${mapping.container_port},\n          \"hostPort\": ${mapping.host_port},\n          \"protocol\": \"${mapping.protocol}\"\n        }%{ if !is_last(mapping) ~},%{ endif ~}\n        %{ endfor ~}\n      ]\n    }\n  ]\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-14\">\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u69cb\u9020\u5316\u3068\u7ba1\u7406\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u304a\u3051\u308b\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u52b9\u679c\u7684\u306a\u7ba1\u7406\u65b9\u6cd5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">project\/\n\u251c\u2500\u2500 main.tf\n\u251c\u2500\u2500 variables.tf\n\u251c\u2500\u2500 outputs.tf\n\u251c\u2500\u2500 locals.tf\n\u251c\u2500\u2500 templates\/\n\u2502   \u251c\u2500\u2500 app\/\n\u2502   \u2502   \u251c\u2500\u2500 config.json.tpl\n\u2502   \u2502   \u2514\u2500\u2500 init.sh.tpl\n\u2502   \u251c\u2500\u2500 iam\/\n\u2502   \u2502   \u251c\u2500\u2500 policies\/\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 s3_access.json.tpl\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 rds_access.json.tpl\n\u2502   \u2502   \u2514\u2500\u2500 roles\/\n\u2502   \u2502       \u2514\u2500\u2500 service_role.json.tpl\n\u2502   \u2514\u2500\u2500 monitoring\/\n\u2502       \u251c\u2500\u2500 cloudwatch_agent.json.tpl\n\u2502       \u2514\u2500\u2500 alerts.json.tpl\n\u2514\u2500\u2500 modules\/\n    \u251c\u2500\u2500 app\/\n    \u2502   \u2514\u2500\u2500 templates\/\n    \u2502       \u2514\u2500\u2500 specific_config.json.tpl\n    \u2514\u2500\u2500 database\/\n        \u2514\u2500\u2500 templates\/\n            \u2514\u2500\u2500 parameter_group.json.tpl<\/pre>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u518d\u5229\u7528\u6027\u3092\u9ad8\u3081\u308b\u305f\u3081\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u5316\u306e\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># modules\/iam\/main.tf\nmodule \"service_role\" {\n  source = \".\/modules\/iam\"\n\n  template_vars = {\n    service_name = var.service_name\n    environment  = var.environment\n    permissions  = var.required_permissions\n  }\n}\n\n# modules\/iam\/templates\/role.json.tpl\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        %{ for permission in permissions ~}\n        \"${permission}\"%{ if !is_last(permission) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"Resource\": [\n        \"arn:aws:${service_name}:*:*:${environment}-*\"\n      ]\n    }\n  ]\n}<\/pre>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u7ba1\u7406\u3068\u30d0\u30fc\u30b8\u30e7\u30cb\u30f3\u30b0\u306e\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># versions.tf\nterraform {\n  required_version = \"&gt;= 1.0.0\"\n\n  required_providers {\n    aws = {\n      source  = \"hashicorp\/aws\"\n      version = \"~&gt; 4.0\"\n    }\n  }\n}\n\n# template_versions.tf\nlocals {\n  template_versions = {\n    app_config     = \"v1.2.0\"\n    iam_policies   = \"v2.0.1\"\n    init_scripts   = \"v1.0.3\"\n  }\n\n  template_path = \"${path.module}\/templates\/${local.template_versions[var.template_type]}\"\n}<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u9069\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u3088\u308a\u4fdd\u5b88\u6027\u304c\u9ad8\u304f\u3001\u5b89\u5168\u306aTerraform\u30b3\u30fc\u30c9\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002\u7279\u306b\u5927\u898f\u6a21\u306a\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3084\u3001\u30c1\u30fc\u30e0\u3067\u306e\u958b\u767a\u306b\u304a\u3044\u3066\u3001\u3053\u308c\u3089\u306e\u898f\u7d04\u306f\u91cd\u8981\u306a\u5f79\u5272\u3092\u679c\u305f\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-15\">\u904b\u7528\u52b9\u7387\u3092\u9ad8\u3081\u308btemplatefile\u6d3b\u7528\u8853<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-16\">\u30c6\u30b9\u30c8\u3068\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u81ea\u52d5\u5316\u624b\u6cd5<\/h3>\n\n\n\n<p>templatefile\u95a2\u6570\u3092\u4f7f\u7528\u3057\u305f\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u306e\u30c6\u30b9\u30c8\u3068\u691c\u8a3c\u3092\u81ea\u52d5\u5316\u3059\u308b\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># tests\/templates_test.go\npackage test\n\nimport (\n    \"testing\"\n    \"encoding\/json\"\n    \"github.com\/gruntwork-io\/terratest\/modules\/terraform\"\n    \"github.com\/stretchr\/testify\/assert\"\n)\n\nfunc TestTemplateRendering(t *testing.T) {\n    t.Run(\"IAM Policy Template\", func(t *testing.T) {\n        terraformOptions := &amp;terraform.Options{\n            TerraformDir: \"..\/\",\n            Vars: map[string]interface{}{\n                \"environment\": \"test\",\n                \"service_name\": \"api\",\n                \"allowed_actions\": []string{\"s3:GetObject\", \"s3:PutObject\"},\n            },\n        }\n\n        output := terraform.Output(t, terraformOptions, \"rendered_policy\")\n        var policy map[string]interface{}\n        err := json.Unmarshal([]byte(output), &amp;policy)\n\n        assert.NoError(t, err)\n        assert.Contains(t, policy[\"Statement\"], \"s3:GetObject\")\n    })\n}<\/pre>\n\n\n\n<p>CI\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u3067\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u691c\u8a3c\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># .github\/workflows\/terraform-validate.yml\nname: Validate Templates\n\non:\n  push:\n    paths:\n      - '**.tpl'\n      - '**.tf'\n\njobs:\n  validate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v2\n\n      - name: Setup Terraform\n        uses: hashicorp\/setup-terraform@v1\n\n      - name: Validate Templates\n        run: |\n          for tpl in $(find . -name \"*.tpl\"); do\n            echo \"Validating $tpl\"\n            terraform console &lt;&lt;EOF\n            templatefile(\"$tpl\", {\n              environment = \"test\"\n              region = \"us-west-2\"\n              service_name = \"test-service\"\n            })\n            EOF\n          done<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">\u30c1\u30fc\u30e0\u958b\u767a\u306b\u304a\u3051\u308b\u6a19\u6e96\u5316\u30a2\u30d7\u30ed\u30fc\u30c1<\/h3>\n\n\n\n<p>\u30c1\u30fc\u30e0\u3067\u306e\u52b9\u7387\u7684\u306a\u958b\u767a\u3092\u5b9f\u73fe\u3059\u308b\u305f\u3081\u306e\u6a19\u6e96\u5316\u624b\u6cd5\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># modules\/template-validator\/main.tf\nmodule \"template_validator\" {\n  source = \".\/modules\/template-validator\"\n\n  templates_path = \"${path.module}\/templates\"\n  validation_rules = {\n    required_variables = [\"environment\", \"service_name\"]\n    allowed_environments = [\"dev\", \"stg\", \"prod\"]\n    naming_convention = \"^[a-z][a-z0-9-]*$\"\n  }\n}\n\n# Pre-commit hook for template validation\n# .pre-commit-config.yaml\nrepos:\n  - repo: local\n    hooks:\n      - id: terraform-template-validate\n        name: Terraform Template Validation\n        entry: scripts\/validate-templates.sh\n        language: script\n        files: \\.(tpl|tf)$<\/pre>\n\n\n\n<p>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u751f\u6210\u306e\u305f\u3081\u306e\u88dc\u52a9\u30c4\u30fc\u30eb\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#!\/bin\/bash\n# scripts\/create-template.sh\n\ntemplate_type=$1\nname=$2\n\ncase $template_type in\n  \"iam\")\n    template_content='\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        %{ for action in actions ~}\n        \"${action}\"%{ if !is_last(action) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"Resource\": [\"${resource_arn}\"]\n    }\n  ]\n}'\n    ;;\n  \"config\")\n    template_content='\n{\n  \"app\": {\n    \"name\": \"${app_name}\",\n    \"environment\": \"${environment}\",\n    \"region\": \"${region}\",\n    \"config\": {\n      %{ for key, value in config ~}\n      \"${key}\": \"${value}\"%{ if !is_last(key) ~},%{ endif ~}\n      %{ endfor ~}\n    }\n  }\n}'\n    ;;\nesac\n\necho \"$template_content\" &gt; \"templates\/${name}.tpl\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-18\">\u65e2\u5b58\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u306e\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u6226\u7565<\/h3>\n\n\n\n<p>\u65e2\u5b58\u306e\u30a4\u30f3\u30d5\u30e9\u30b3\u30fc\u30c9\u3092templatefile\u95a2\u6570\u3092\u4f7f\u7528\u3057\u3066\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u3059\u308b\u6226\u7565\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Before: \u76f4\u63a5\u57cb\u3081\u8fbc\u307e\u308c\u305f\u30dd\u30ea\u30b7\u30fc\nresource \"aws_iam_role_policy\" \"example\" {\n  name = \"example-policy\"\n  role = aws_iam_role.example.id\n\n  policy = &lt;&lt;EOF\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:GetObject\",\n        \"s3:PutObject\"\n      ],\n      \"Resource\": [\n        \"arn:aws:s3:::example-bucket\/*\"\n      ]\n    }\n  ]\n}\nEOF\n}\n\n# After: \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5316\u3055\u308c\u305f\u30dd\u30ea\u30b7\u30fc\n# templates\/policies\/s3_access.json.tpl\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        %{ for action in allowed_actions ~}\n        \"${action}\"%{ if !is_last(action) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"Resource\": [\n        %{ for bucket in buckets ~}\n        \"arn:aws:s3:::${bucket}\/*\"%{ if !is_last(bucket) ~},%{ endif ~}\n        %{ endfor ~}\n      ]\n    }\n  ]\n}\n\n# main.tf\nresource \"aws_iam_role_policy\" \"example\" {\n  name = \"example-policy\"\n  role = aws_iam_role.example.id\n\n  policy = templatefile(\"${path.module}\/templates\/policies\/s3_access.json.tpl\", {\n    allowed_actions = var.s3_actions\n    buckets        = var.target_buckets\n  })\n}<\/pre>\n\n\n\n<p>\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u306e\u305f\u3081\u306e\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5316\u306e\u5019\u88dc\u3092\u7279\u5b9a<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8907\u6570\u306e\u5834\u6240\u3067\u4f7f\u7528\u3055\u308c\u308b\u4f3c\u305f\u3088\u3046\u306a\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u74b0\u5883\u3084\u30ea\u30fc\u30b8\u30e7\u30f3\u306b\u3088\u3063\u3066\u7570\u306a\u308b\u5024<\/li>\n\n\n\n<li>\u9577\u3044\u6587\u5b57\u5217\u3084JSON\/YAML\u5f62\u5f0f\u306e\u8a2d\u5b9a<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u5909\u6570\u306e\u62bd\u51fa\u3068\u6574\u7406<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5171\u901a\u306e\u5909\u6570\u3092variables.tf\u306b\u5b9a\u7fa9<\/li>\n\n\n\n<li>\u74b0\u5883\u56fa\u6709\u306e\u5024\u3092terraform.tfvars\u3067\u7ba1\u7406<\/li>\n\n\n\n<li>\u30ed\u30fc\u30ab\u30eb\u5909\u6570\u306b\u3088\u308b\u4e2d\u9593\u30c7\u30fc\u30bf\u306e\u6574\u7406<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u3068\u691c\u8a3c<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9069\u5207\u306a\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u69cb\u9020\u306e\u4f5c\u6210<\/li>\n\n\n\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3<\/li>\n\n\n\n<li>\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\u306e\u4f5c\u6210<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u6bb5\u968e\u7684\u306a\u79fb\u884c<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1\u3064\u306e\u30ea\u30bd\u30fc\u30b9\u305a\u3064\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5316<\/li>\n\n\n\n<li>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210<\/li>\n\n\n\n<li>apply\u8a08\u753b\u306e\u614e\u91cd\u306a\u78ba\u8a8d<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u306e\u3088\u3046\u306b\u3001\u904b\u7528\u52b9\u7387\u3092\u9ad8\u3081\u308b\u305f\u3081\u306b\u306f\u3001\u81ea\u52d5\u5316\u3055\u308c\u305f\u30c6\u30b9\u30c8\u3001\u6a19\u6e96\u5316\u3055\u308c\u305f\u30a2\u30d7\u30ed\u30fc\u30c1\u3001\u305d\u3057\u3066\u8a08\u753b\u7684\u306a\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u304c\u91cd\u8981\u3067\u3059\u3002\u3053\u308c\u3089\u306e\u65bd\u7b56\u306b\u3088\u308a\u3001\u30c1\u30fc\u30e0\u5168\u4f53\u306e\u751f\u7523\u6027\u304c\u5411\u4e0a\u3057\u3001\u3088\u308a\u4fe1\u983c\u6027\u306e\u9ad8\u3044\u30a4\u30f3\u30d5\u30e9\u7ba1\u7406\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-19\">\u3088\u304f\u3042\u308b\u30a8\u30e9\u30fc\u3068\u89e3\u6c7a\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-20\">\u69cb\u6587\u30a8\u30e9\u30fc\u306e\u4e3b\u306a\u539f\u56e0\u3068\u5bfe\u51e6\u6cd5<\/h3>\n\n\n\n<p>templatefile\u95a2\u6570\u4f7f\u7528\u6642\u306b\u3088\u304f\u906d\u9047\u3059\u308b\u69cb\u6587\u30a8\u30e9\u30fc\u3068\u305d\u306e\u89e3\u6c7a\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5909\u6570\u53c2\u7167\u30a8\u30e9\u30fc<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30a8\u30e9\u30fc\u30d1\u30bf\u30fc\u30f31: \u672a\u5b9a\u7fa9\u5909\u6570\u306e\u53c2\u7167\n# template.tpl\n${undefined_variable}  # Error: Reference to undeclared input variable\n\n# \u89e3\u6c7a\u65b9\u6cd5\nvariable \"my_variable\" {\n  description = \"Template \u3067\u4f7f\u7528\u3059\u308b\u5909\u6570\"\n  type        = string\n}\n\n# \u4fee\u6b63\u5f8c\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4f7f\u7528\u4f8b\ntemplatefile(\"${path.module}\/template.tpl\", {\n  my_variable = var.my_variable\n})<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u5236\u5fa1\u69cb\u6587\u306e\u30b7\u30f3\u30bf\u30c3\u30af\u30b9\u30a8\u30e9\u30fc<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30a8\u30e9\u30fc\u30d1\u30bf\u30fc\u30f32: for\u6587\u306e\u69cb\u6587\u30df\u30b9\n# bad_template.tpl\n%{ for item in items }  # Missing ~\n  ${item}\n%{ endfor }  # Missing ~\n\n# \u89e3\u6c7a\u65b9\u6cd5: \u6b63\u3057\u3044\u69cb\u6587\n# good_template.tpl\n%{ for item in items ~}\n  ${item}\n%{ endfor ~}\n\n# \u4f7f\u7528\u4f8b\ntemplatefile(\"${path.module}\/good_template.tpl\", {\n  items = [\"item1\", \"item2\", \"item3\"]\n})<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>JSON\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u30a8\u30e9\u30fc<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30a8\u30e9\u30fc\u30d1\u30bf\u30fc\u30f33: JSON\u69cb\u6587\u306e\u4e0d\u6b63\n# bad_json.tpl\n{\n  \"items\": [\n    %{ for item in items ~}\n    \"${item}\"   # \u6700\u5f8c\u306e\u30ab\u30f3\u30de\u51e6\u7406\u304c\u4e0d\u9069\u5207\n    %{ endfor ~}\n  ]\n}\n\n# \u89e3\u6c7a\u65b9\u6cd5: is_last\u95a2\u6570\u306e\u4f7f\u7528\n# good_json.tpl\n{\n  \"items\": [\n    %{ for item in items ~}\n    \"${item}\"%{ if !is_last(item) ~},%{ endif ~}\n    %{ endfor ~}\n  ]\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">\u5909\u6570\u53c2\u7167\u306b\u95a2\u3059\u308b\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0<\/h3>\n\n\n\n<p>\u5909\u6570\u53c2\u7167\u3067\u767a\u751f\u3059\u308b\u4e00\u822c\u7684\u306a\u554f\u984c\u3068\u305d\u306e\u89e3\u6c7a\u30a2\u30d7\u30ed\u30fc\u30c1\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30b9\u30b3\u30fc\u30d7\u306e\u554f\u984c<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30a8\u30e9\u30fc\u30d1\u30bf\u30fc\u30f34: \u5909\u6570\u30b9\u30b3\u30fc\u30d7\u306e\u8aa4\u308a\nmodule \"example\" {\n  source = \".\/modules\/example\"\n\n  # \u76f4\u63a5templatefile\u3092\u547c\u3073\u51fa\u305d\u3046\u3068\u3059\u308b\n  template_content = templatefile(\"${path.module}\/template.tpl\", {\n    local_var = local.some_value  # Error: Reference to undeclared local value\n  })\n}\n\n# \u89e3\u6c7a\u65b9\u6cd5: \u5909\u6570\u306e\u9069\u5207\u306a\u53d7\u3051\u6e21\u3057\n# modules\/example\/variables.tf\nvariable \"template_vars\" {\n  description = \"\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3067\u4f7f\u7528\u3059\u308b\u5909\u6570\u306e\u30de\u30c3\u30d7\"\n  type        = map(any)\n}\n\n# modules\/example\/main.tf\nlocals {\n  template_content = templatefile(\"${path.module}\/template.tpl\", var.template_vars)\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u578b\u306e\u4e0d\u4e00\u81f4<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30a8\u30e9\u30fc\u30d1\u30bf\u30fc\u30f35: \u578b\u306e\u4e0d\u4e00\u81f4\n# template.tpl\n\"port\": ${port}  # \u6587\u5b57\u5217\u3068\u3057\u3066\u4f7f\u7528\u3057\u305f\u3044\u6570\u5024\n\n# \u89e3\u6c7a\u65b9\u6cd5: \u660e\u793a\u7684\u306a\u578b\u5909\u63db\n# \u6570\u5024\u3092\u6587\u5b57\u5217\u3068\u3057\u3066\u6271\u3046\u5834\u5408\n\"port\": \"${tostring(port)}\"\n\n# \u30ea\u30b9\u30c8\u3092\u6587\u5b57\u5217\u3068\u3057\u3066\u7d50\u5408\u3059\u308b\u5834\u5408\n\"commands\": \"${join(\" &amp;&amp; \", commands)}\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-22\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30d2\u30f3\u30c8<\/h3>\n\n\n\n<p>templatefile\u95a2\u6570\u4f7f\u7528\u6642\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u975e\u52b9\u7387\u306a\u5b9f\u88c5\nresource \"aws_instance\" \"example\" {\n  count = length(var.instances)\n\n  user_data = templatefile(\"${path.module}\/init.sh.tpl\", {\n    instance_name = var.instances[count.index].name\n    # \u6bce\u56de\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u8aad\u307f\u8fbc\u3080\n  })\n}\n\n# \u6700\u9069\u5316\u3055\u308c\u305f\u5b9f\u88c5\nlocals {\n  template_cache = templatefile(\"${path.module}\/init.sh.tpl\", {\n    instances = var.instances\n  })\n}\n\nresource \"aws_instance\" \"example\" {\n  count = length(var.instances)\n\n  user_data = local.template_cache\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u6761\u4ef6\u4ed8\u304d\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u8aad\u307f\u8fbc\u307f<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u52b9\u7387\u7684\u306a\u6761\u4ef6\u4ed8\u304d\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4f7f\u7528\nlocals {\n  template_file = var.environment == \"prod\" ? \"prod.tpl\" : \"dev.tpl\"\n\n  config = templatefile(\"${path.module}\/templates\/${local.template_file}\", {\n    environment = var.environment\n    settings    = var.environment_settings[var.environment]\n  })\n}<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u5927\u304d\u306a\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u5206\u5272<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u5927\u304d\u306a\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u7ba1\u7406\u53ef\u80fd\u306a\u30b5\u30a4\u30ba\u306b\u5206\u5272\nlocals {\n  base_config = templatefile(\"${path.module}\/templates\/base.tpl\", {\n    environment = var.environment\n  })\n\n  service_config = templatefile(\"${path.module}\/templates\/service.tpl\", {\n    services = var.service_definitions\n  })\n\n  monitoring_config = templatefile(\"${path.module}\/templates\/monitoring.tpl\", {\n    alerts = var.alert_definitions\n  })\n\n  # \u5fc5\u8981\u306b\u5fdc\u3058\u3066\u7d50\u5408\n  combined_config = jsonencode({\n    base       = jsondecode(local.base_config)\n    services   = jsondecode(local.service_config)\n    monitoring = jsondecode(local.monitoring_config)\n  })\n}<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u554f\u984c\u89e3\u6c7a\u30a2\u30d7\u30ed\u30fc\u30c1\u3068\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u624b\u6cd5\u3092\u9069\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u3088\u308a\u5b89\u5b9a\u3057\u305f\u904b\u7528\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002\u7279\u306b\u5927\u898f\u6a21\u306a\u30a4\u30f3\u30d5\u30e9\u69cb\u6210\u3067\u306f\u3001\u3053\u308c\u3089\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u304c\u91cd\u8981\u306a\u5f79\u5272\u3092\u679c\u305f\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-23\">\u5fdc\u7528\uff1a\u5927\u898f\u6a21\u30b7\u30b9\u30c6\u30e0\u306b\u304a\u3051\u308btemplatefile\u6d3b\u7528\u4e8b\u4f8b<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-24\">\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u3067\u306e\u30de\u30eb\u30c1\u6d3b\u7528\u4f8b<\/h3>\n\n\n\n<p>\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306b\u304a\u3051\u308btemplatefile\u95a2\u6570\u306e\u52b9\u679c\u7684\u306a\u6d3b\u7528\u65b9\u6cd5\u3092\u7d39\u4ecb\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># microservices\/service.tf\nmodule \"microservice\" {\n  source = \".\/modules\/microservice\"\n\n  for_each = local.services\n\n  name           = each.key\n  configuration  = each.value\n  environment    = var.environment\n  region         = var.aws_region\n}\n\n# modules\/microservice\/templates\/task-definition.json.tpl\n{\n  \"family\": \"${service_name}\",\n  \"containerDefinitions\": [\n    {\n      \"name\": \"${service_name}\",\n      \"image\": \"${ecr_repository}:${image_tag}\",\n      \"cpu\": ${cpu},\n      \"memory\": ${memory},\n      \"essential\": true,\n      \"portMappings\": [\n        %{ for port in port_mappings ~}\n        {\n          \"containerPort\": ${port.container},\n          \"hostPort\": ${port.host},\n          \"protocol\": \"${port.protocol}\"\n        }%{ if !is_last(port) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"environment\": [\n        %{ for key, value in environment_variables ~}\n        {\n          \"name\": \"${key}\",\n          \"value\": \"${value}\"\n        }%{ if !is_last(key) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"logConfiguration\": {\n        \"logDriver\": \"awslogs\",\n        \"options\": {\n          \"awslogs-group\": \"\/ecs\/${service_name}\",\n          \"awslogs-region\": \"${region}\",\n          \"awslogs-stream-prefix\": \"${environment}\"\n        }\n      },\n      \"healthCheck\": {\n        \"command\": ${jsonencode(health_check_command)},\n        \"interval\": ${health_check_interval},\n        \"timeout\": ${health_check_timeout},\n        \"retries\": ${health_check_retries}\n      }\n    }\n  ],\n  \"executionRoleArn\": \"${execution_role_arn}\",\n  \"taskRoleArn\": \"${task_role_arn}\",\n  \"networkMode\": \"awsvpc\",\n  \"requiresCompatibilities\": [\"FARGATE\"],\n  \"cpu\": \"${cpu}\",\n  \"memory\": \"${memory}\"\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-25\">\u30a2\u30ab\u30a6\u30f3\u30c8\u6226\u7565\u3067\u306e\u5b9f\u73fe\u30d1\u30bf\u30fc\u30f3<\/h3>\n\n\n\n<p>\u30de\u30eb\u30c1\u30a2\u30ab\u30a6\u30f3\u30c8\u74b0\u5883\u3067\u306etemplatefile\u6d3b\u7528\u30d1\u30bf\u30fc\u30f3\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># organization\/account_setup.tf\nlocals {\n  account_config = jsondecode(templatefile(\"${path.module}\/templates\/account_config.json.tpl\", {\n    organization_id = var.organization_id\n    environments   = var.environments\n    service_names  = var.service_names\n  }))\n}\n\n# templates\/account_config.json.tpl\n{\n  \"accounts\": {\n    %{ for env in environments ~}\n    \"${env}\": {\n      \"name\": \"${env}-environment\",\n      \"email\": \"aws+${env}@example.com\",\n      \"services\": {\n        %{ for service in service_names ~}\n        \"${service}\": {\n          \"vpc_cidr\": \"10.${index(environments, env)}.${index(service_names, service)}.0\/24\",\n          \"private_subnets\": [\n            \"10.${index(environments, env)}.${index(service_names, service)}.0\/26\",\n            \"10.${index(environments, env)}.${index(service_names, service)}.64\/26\"\n          ]\n        }%{ if !is_last(service) ~},%{ endif ~}\n        %{ endfor ~}\n      }\n    }%{ if !is_last(env) ~},%{ endif ~}\n    %{ endfor ~}\n  }\n}\n\n# IAM\u30dd\u30ea\u30b7\u30fc\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\n# templates\/cross_account_policy.json.tpl\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        %{ for action in allowed_actions ~}\n        \"${action}\"%{ if !is_last(action) ~},%{ endif ~}\n        %{ endfor ~}\n      ],\n      \"Resource\": [\n        %{ for account in target_accounts ~}\n        \"arn:aws:${service}:${region}:${account}:${resource_path}\"\n        %{ if !is_last(account) ~},%{ endif ~}\n        %{ endfor ~}\n      ]\n    }\n  ]\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-26\">\u7d99\u7d9a\u7684\u306a\u30c7\u30ea\u30d0\u30ea\u30fc\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u3067\u306e\u7d71\u5408\u65b9\u6cd5<\/h3>\n\n\n\n<p>CI\/CD\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u3067\u306etemplatefile\u6d3b\u7528\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># pipeline\/main.tf\nmodule \"codepipeline\" {\n  source = \".\/modules\/pipeline\"\n\n  for_each = local.service_pipelines\n\n  pipeline_config = templatefile(\"${path.module}\/templates\/pipeline_config.json.tpl\", {\n    service_name = each.key\n    environments = var.deployment_environments\n    repository   = each.value.repository\n    branch       = each.value.branch\n    build_spec   = each.value.build_spec\n  })\n}\n\n# templates\/pipeline_config.json.tpl\n{\n  \"pipeline\": {\n    \"name\": \"${service_name}-pipeline\",\n    \"stages\": [\n      {\n        \"name\": \"Source\",\n        \"actions\": [\n          {\n            \"name\": \"Source\",\n            \"category\": \"Source\",\n            \"provider\": \"CodeCommit\",\n            \"configuration\": {\n              \"RepositoryName\": \"${repository}\",\n              \"BranchName\": \"${branch}\"\n            }\n          }\n        ]\n      },\n      %{ for env in environments ~}\n      {\n        \"name\": \"Deploy-to-${env}\",\n        \"actions\": [\n          {\n            \"name\": \"Deploy\",\n            \"category\": \"Deploy\",\n            \"provider\": \"CloudFormation\",\n            \"configuration\": {\n              \"StackName\": \"${service_name}-${env}\",\n              \"TemplatePath\": \"BuildOutput::template.yaml\",\n              \"Capabilities\": \"CAPABILITY_IAM\",\n              \"ParameterOverrides\": {\n                \"Environment\": \"${env}\",\n                \"ServiceName\": \"${service_name}\"\n              }\n            }\n          }\n        ]%{ if !is_last(env) ~},%{ endif ~}\n      }\n      %{ endfor ~}\n    ]\n  }\n}\n\n# \u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u8a2d\u5b9a\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\n# templates\/deployment_config.json.tpl\n{\n  \"version\": 1.0,\n  \"Resources\": [\n    %{ for resource in deployment_resources ~}\n    {\n      \"name\": \"${resource.name}\",\n      \"type\": \"${resource.type}\",\n      \"properties\": {\n        %{ for key, value in resource.properties ~}\n        \"${key}\": ${jsonencode(value)}%{ if !is_last(key) ~},%{ endif ~}\n        %{ endfor ~}\n      }\n    }%{ if !is_last(resource) ~},%{ endif ~}\n    %{ endfor ~}\n  ],\n  \"Hooks\": [\n    %{ for hook in deployment_hooks ~}\n    {\n      \"name\": \"${hook.name}\",\n      \"command\": ${jsonencode(hook.command)},\n      \"timeout\": \"${hook.timeout}\"\n    }%{ if !is_last(hook) ~},%{ endif ~}\n    %{ endfor ~}\n  ]\n}<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30d1\u30bf\u30fc\u30f3\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u5927\u898f\u6a21\u30b7\u30b9\u30c6\u30e0\u306b\u304a\u3044\u3066\u3082\u52b9\u7387\u7684\u306a\u30a4\u30f3\u30d5\u30e9\u30b9\u30c8\u30e9\u30af\u30c1\u30e3\u7ba1\u7406\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002\u7279\u306b\u4ee5\u4e0b\u306e\u70b9\u306b\u6ce8\u610f\u3057\u3066\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3092\u304a\u52e7\u3081\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30e2\u30b8\u30e5\u30fc\u30eb\u5316\u3068\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u518d\u5229\u7528<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5171\u901a\u306e\u30d1\u30bf\u30fc\u30f3\u3092\u30e2\u30b8\u30e5\u30fc\u30eb\u5316<\/li>\n\n\n\n<li>\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u968e\u5c64\u69cb\u9020\u5316<\/li>\n\n\n\n<li>\u30d0\u30fc\u30b8\u30e7\u30f3\u7ba1\u7406\u306e\u5fb9\u5e95<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u74b0\u5883\u9593\u306e\u4e00\u8cab\u6027\u78ba\u4fdd<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u74b0\u5883\u56fa\u6709\u306e\u8a2d\u5b9a\u306e\u5206\u96e2<\/li>\n\n\n\n<li>\u5171\u901a\u8a2d\u5b9a\u306e\u4e00\u5143\u7ba1\u7406<\/li>\n\n\n\n<li>\u5909\u66f4\u5c65\u6b74\u306e\u8ffd\u8de1<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3068\u30b3\u30f3\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30a2\u30af\u30bb\u30b9\u6a29\u9650\u306e\u9069\u5207\u306a\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u76e3\u67fb\u30ed\u30b0\u306e\u78ba\u4fdd<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u306e\u9069\u7528<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u306f\u3001\u7d44\u7e54\u306e\u898f\u6a21\u3084\u8981\u4ef6\u306b\u5fdc\u3058\u3066\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/ &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":{"0":"post-2356","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-aws","7":"nothumb"},"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/2356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2356"}],"version-history":[{"count":1,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/2356\/revisions"}],"predecessor-version":[{"id":2357,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/2356\/revisions\/2357"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}