diff --git a/404.html b/404.html index dec54230..4b897fae 100644 --- a/404.html +++ b/404.html @@ -8,13 +8,13 @@ - + -

404

Looks like we've got some broken links.
+ - + diff --git a/about.html b/about.html index 394016d0..448a86fa 100644 --- a/about.html +++ b/about.html @@ -8,7 +8,7 @@ - + @@ -18,7 +18,7 @@ GitHub (opens new window)

# IIJ Bootcampとは

# 目的

IIJ BootcampIIJ (opens new window) で開催しているハンズオン勉強会です。 各技術が誕生した経緯・歴史、ほかの技術と比較といった知識を得るためのきっかけとして、さまざまな言語・フレームワーク・ツールに触れて実際に動かすハンズオンを行っています。 -カリキュラムにはハンズオンだけでなく、「overview」として技術ジャンルの全体像や歴史などを紹介する回も設けています。

このサイトではIIJ Bootcamp用に社内で作成したハンズオン資料をCC BY-SA (opens new window)ライセンスで公開しています(GitHubリポジトリはこちら (opens new window))。

カリキュラムの全体像や資料へのリンクはトップページをご覧ください。

# 資料の構成

ハンズオン資料は以下のカテゴリに分かれています。

カテゴリ 概要
開発系 開発に必須となるGitやdockerのハンズオン
CI/CD + 構成管理 CIサーバのハンズオンとansibleやk8sによるアプリケーションデプロイ
データベース MySQL, MongoDB, Redis ハンズオン
Webサーバ構築 Apacheやnginxを使ったWebサーバの構築
サーバサイドアプリケーション DjangoやJava、golangを使ったサーバサイドアプリケーションの構築
フロントエンド 流行りのWebフレームワークを一通り触ってみる
セキュリティ Webにおけるセキュリティについてと、脆弱なサーバを作らないためのハンズオン

# 資料の利用と修正

資料は CC BY-SAライセンス (opens new window) で公開されており、勉強会などでの2次利用が可能です。その際資料の間違いや最新情報への更新などが必要な場合は、issue (opens new window)で気軽にお知らせください。

またPullRequestについても歓迎しています。その際は CONTRIBUTING.md (opens new window) をご一読ください。

- +カリキュラムにはハンズオンだけでなく、「overview」として技術ジャンルの全体像や歴史などを紹介する回も設けています。

このサイトではIIJ Bootcamp用に社内で作成したハンズオン資料をCC BY-SA (opens new window)ライセンスで公開しています(GitHubリポジトリはこちら (opens new window))。

カリキュラムの全体像や資料へのリンクはトップページをご覧ください。

# 資料の構成

ハンズオン資料は以下のカテゴリに分かれています。

カテゴリ 概要
開発系 開発に必須となるGitやdockerのハンズオン
CI/CD + 構成管理 CIサーバのハンズオンとansibleやk8sによるアプリケーションデプロイ
データベース MySQL, MongoDB, Redis ハンズオン
Webサーバ構築 Apacheやnginxを使ったWebサーバの構築
サーバサイドアプリケーション DjangoやJava、golangを使ったサーバサイドアプリケーションの構築
フロントエンド 流行りのWebフレームワークを一通り触ってみる
セキュリティ Webにおけるセキュリティについてと、脆弱なサーバを作らないためのハンズオン

# 資料の利用と修正

資料は CC BY-SAライセンス (opens new window) で公開されており、勉強会などでの2次利用が可能です。その際資料の間違いや最新情報への更新などが必要な場合は、issue (opens new window)で気軽にお知らせください。

またPullRequestについても歓迎しています。その際は CONTRIBUTING.md (opens new window) をご一読ください。

+ diff --git a/assets/js/10.3cf2734d.js b/assets/js/10.4f11f457.js similarity index 99% rename from assets/js/10.3cf2734d.js rename to assets/js/10.4f11f457.js index 72130381..34f4142e 100644 --- a/assets/js/10.3cf2734d.js +++ b/assets/js/10.4f11f457.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{461:function(s,t,a){s.exports=a.p+"assets/img/web_app_true1.drawio.c12026f8.png"},462:function(s,t,a){s.exports=a.p+"assets/img/web_app_true2.drawio.d698dacd.png"},463:function(s,t){s.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI0AAAD9CAYAAACBfPRkAAAAAXNSR0IArs4c6QAACPF0RVh0bXhmaWxlACUzQ214ZmlsZSUzRSUzQ2RpYWdyYW0lMjBpZCUzRCUyMmRZdWtSSjdiVUNwY1NTaXVMdmlEJTIyJTIwbmFtZSUzRCUyMiVFMyU4MyU5QSVFMyU4MyVCQyVFMyU4MiVCODElMjIlM0UlM0NteEdyYXBoTW9kZWwlMjBkeCUzRCUyMjcxOSUyMiUyMGR5JTNEJTIyMTA0OSUyMiUyMGdyaWQlM0QlMjIxJTIyJTIwZ3JpZFNpemUlM0QlMjIxMCUyMiUyMGd1aWRlcyUzRCUyMjElMjIlMjB0b29sdGlwcyUzRCUyMjElMjIlMjBjb25uZWN0JTNEJTIyMSUyMiUyMGFycm93cyUzRCUyMjElMjIlMjBmb2xkJTNEJTIyMSUyMiUyMHBhZ2UlM0QlMjIxJTIyJTIwcGFnZVNjYWxlJTNEJTIyMSUyMiUyMHBhZ2VXaWR0aCUzRCUyMjgyNyUyMiUyMHBhZ2VIZWlnaHQlM0QlMjIxMTY5JTIyJTIwYmFja2dyb3VuZCUzRCUyMiUyM2ZmZmZmZiUyMiUyMG1hdGglM0QlMjIwJTIyJTIwc2hhZG93JTNEJTIyMCUyMiUzRSUzQ3Jvb3QlM0UlM0NteENlbGwlMjBpZCUzRCUyMjAlMjIlMkYlM0UlM0NteENlbGwlMjBpZCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIwJTIyJTJGJTNFJTNDbXhDZWxsJTIwaWQlM0QlMjIxMSUyMiUyMHZhbHVlJTNEJTIyJUUzJTgyJUI1JUUzJTgyJUE0JUUzJTgzJTg4JUU5JTk2JUIyJUU4JUE2JUE3JTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0Rub25lJTNCaHRtbCUzRDElM0JleGl0WCUzRDAuMjUlM0JleGl0WSUzRDAlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRDAuMjUlM0JlbnRyeVklM0QxJTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQiUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjI1JTIyJTIwdGFyZ2V0JTNEJTIyMTQlMjIlMjBlZGdlJTNEJTIyMSUyMiUzRSUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTJGJTNFJTNDJTJGbXhDZWxsJTNFJTNDbXhDZWxsJTIwaWQlM0QlMjI1JTIyJTIwdmFsdWUlM0QlMjJXZWIlRTMlODMlOTYlRTMlODMlQTklRTMlODIlQTYlRTMlODIlQjYlMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0JodG1sJTNEMSUzQiUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTNFJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI0MCUyMiUyMHklM0QlMjIxOTAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjYwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyRiUzRSUzQyUyRm14Q2VsbCUzRSUzQ214Q2VsbCUyMGlkJTNEJTIyMTMlMjIlMjB2YWx1ZSUzRCUyMkhUTUwlMjIlMjBzdHlsZSUzRCUyMmVkZ2VTdHlsZSUzRG5vbmUlM0JodG1sJTNEMSUzQmV4aXRYJTNEMC43NSUzQmV4aXRZJTNEMSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMC43NSUzQmVudHJ5WSUzRDAlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMjE0JTIyJTIwdGFyZ2V0JTNEJTIyNSUyMiUyMGVkZ2UlM0QlMjIxJTIyJTNFJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMkYlM0UlM0MlMkZteENlbGwlM0UlM0NteENlbGwlMjBpZCUzRCUyMjIlMjIlMjB2YWx1ZSUzRCUyMkFjdG9yJTIyJTIwc3R5bGUlM0QlMjJzaGFwZSUzRHVtbEFjdG9yJTNCdmVydGljYWxMYWJlbFBvc2l0aW9uJTNEYm90dG9tJTNCdmVydGljYWxBbGlnbiUzRHRvcCUzQmh0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"},464:function(s,t,a){s.exports=a.p+"assets/img/web_app_true3.drawio.45cb353d.png"},465:function(s,t,a){s.exports=a.p+"assets/img/perl_cgi.drawio.c9857297.png"},466:function(s,t,a){s.exports=a.p+"assets/img/mod_perl.drawio.80a12876.png"},467:function(s,t,a){s.exports=a.p+"assets/img/apache_rails.drawio.7dadfe95.png"},468:function(s,t,a){s.exports=a.p+"assets/img/event-loop.08b77931.png"},469:function(s,t,a){s.exports=a.p+"assets/img/node.drawio.0548a511.png"},470:function(s,t,a){s.exports=a.p+"assets/img/go.drawio.c70b0a4e.png"},471:function(s,t,a){s.exports=a.p+"assets/img/open_api_1.fde7ab4c.png"},472:function(s,t,a){s.exports=a.p+"assets/img/open_api_2.5bbd593d.png"},543:function(s,t,a){"use strict";a.r(t);var n=a(10),e=Object(n.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"サーバアプリケーション界隈overview"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#サーバアプリケーション界隈overview"}},[s._v("#")]),s._v(" サーバアプリケーション界隈Overview")]),s._v(" "),t("h2",{attrs:{id:"webアプリケーションとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#webアプリケーションとは"}},[s._v("#")]),s._v(" Webアプリケーションとは?")]),s._v(" "),t("p",[s._v("世の中はWebアプリケーションで溢れています。")]),s._v(" "),t("p",[s._v("この図の「Ruby on Rails」と書かれているのはWebアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(461),alt:"web_app_true1.png",title:"web_app_true1"}})]),s._v(" "),t("p",[s._v("次の図の「Perl CGI」もWebアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(462),alt:"web_app_true2.png",title:"web_app_true2"}})]),s._v(" "),t("p",[s._v("次の図の「Apache」はWebアプリケーションじゃない。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(463),alt:"web_app_false1.png",title:"web_app_false1"}})]),s._v(" "),t("p",[s._v("次の図の「Go」は多分Webアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(464),alt:"web_app_true3.png",title:"web_app_true3"}})]),s._v(" "),t("p",[s._v("明確な定義はありませんが、サーバ上で動作しHTTPなどの仕組みを利用してWeb上からアクセスされること、DBなどと連携し何らかの動的な結果を返すアプリケーションのことを呼びます。")]),s._v(" "),t("h2",{attrs:{id:"色々なwebアプリケーションの実装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#色々なwebアプリケーションの実装"}},[s._v("#")]),s._v(" 色々なWebアプリケーションの実装")]),s._v(" "),t("p",[s._v("Webアプリケーションはwebの発展と共に様々な「書き方」と「動かし方」が提案されていました。\n書き方が同じでも動かし方が変わったもの、言語を含めて書き方だけが違うやり方、様々です。")]),s._v(" "),t("p",[s._v("この章では様々なWebアプリケーションの実装を「書き方」と「動かし方」それぞれの面で見ていきます。\n大体登場した歴史順に紹介しますが、必ずしも新しいものが正しい・素晴らしいというわけではなく、「得意なユースケースは何か?」がポイントとなります。")]),s._v(" "),t("h3",{attrs:{id:"cgi"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#cgi"}},[s._v("#")]),s._v(" CGI")]),s._v(" "),t("p",[s._v("(1993年 フォーマルな"),t("a",{attrs:{href:"https://www.w3.org/CGI/",target:"_blank",rel:"noopener noreferrer"}},[s._v("仕様"),t("OutboundLink")],1),s._v("制定は1997年)")]),s._v(" "),t("div",{staticClass:"language-perl line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-perl"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#!/usr/bin/perl")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Content-type: text/html \\n\\n"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"

Welcome to IIJ Bootcamp

"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("ul",[t("li",[s._v("Common Gateway Interface の略")]),s._v(" "),t("li",[s._v('The Apache HTTP Server ("httpd") などのWebサーバでHTTPリクエストを受けて、外部プログラムにHTTPリクエストを渡し、出力をHTTPレスポンスとして返すしくみ。')]),s._v(" "),t("li",[s._v("Perlが大流行するきっかけとなった。\n"),t("ul",[t("li",[s._v("Perlは文字列処理が強力(C言語は文字列処理が貧弱)")]),s._v(" "),t("li",[s._v("PerlからMySQL/PostgreSQLに接続してHTTPレスポンスを生成するスタイル")])])]),s._v(" "),t("li",[s._v("今日でもPerlで実装されたプロダクトは存続している(MovableTypeとか、mixiとか。CookPadもPerlでスタートしたはず)。")]),s._v(" "),t("li",[s._v("CGIの仕組み自体はPerl以外でもRubyやPython、シェルスクリプトなど文字列を出力できるプログラムであれば利用できる")])]),s._v(" "),t("p",[s._v("CGIはHTTPリクエストを受けるごとに、新しいプロセスをforkする必要があり、Webサーバにとって負荷が高かった。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(465),alt:"perl_cgi",title:"perl_cgi"}})]),s._v(" "),t("p",[s._v("WebサーバのモジュールとしてPerlを動作させる「mod_perl」という方法が考案された(apache httpd + mod_perl 1998年)")]),s._v(" "),t("p",[t("img",{attrs:{src:a(466),alt:"mod_perl",title:"mod_perl"}})]),s._v(" "),t("h3",{attrs:{id:"php"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#php"}},[s._v("#")]),s._v(" PHP")]),s._v(" "),t("div",{staticClass:"language-php line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-php"}},[t("code",[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("html")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("head")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("title")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("IIJ Bootcamp"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("body")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token php language-php"}},[t("span",{pre:!0,attrs:{class:"token delimiter important"}},[s._v("Welcom to IIJ Bootcamp

'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token delimiter important"}},[s._v("?>")])]),s._v(" \n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br")])]),t("p",[s._v("(開発開始は1994年 実質的に最初の公開版PHP 3が1997年 本格普及はPHP 4で2000年)")]),s._v(" "),t("ol",[t("li",[s._v("CGIはHTTPリクエストを受けるごとに、新しいプロセスをforkする必要があり、Webサーバにとって負荷が高かった。")]),s._v(" "),t("li",[s._v("前述の通りmod_perlという形でPerlを動作させる手法が流行っていた")]),s._v(" "),t("li",[s._v("しかし当然ながらPerlはWebサーバのモジュールとして動作させる前提で設計・実装されたものではなく、使い勝手が悪かった")]),s._v(" "),t("li",[s._v("類似の技術としてFastCGIというものもあったが、やはり癖があり使いにくかった")]),s._v(" "),t("li",[s._v("そこで最初からWebサーバのモジュールとして実行することを念頭に置いた、Webプログラミングに特化した処理系としてPHPが登場、大流行してPerlを駆逐する。\n"),t("ol",[t("li",[s._v("Facebookも長い間PHPで書かれていた。")])])]),s._v(" "),t("li",[s._v("元々はWebページを動的に生成するためのテンプレート的な言語であったが、機能が追加された結果スクリプト言語としての機能も持つ")]),s._v(" "),t("li",[s._v("動かし方はCGI, mod_php(モジュール形式)などがあり、Perlの項目とほぼ同様の形式で動作する")]),s._v(" "),t("li",[s._v("現在でも広く利用されており、"),t("a",{attrs:{href:"https://cakephp.org/jp",target:"_blank",rel:"noopener noreferrer"}},[s._v("CakePHP"),t("OutboundLink")],1),s._v(" など今風のフレームワークも存在する")])]),s._v(" "),t("h3",{attrs:{id:"java-servlet-サーブレット"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#java-servlet-サーブレット"}},[s._v("#")]),s._v(" Java Servlet (サーブレット)")]),s._v(" "),t("p",[s._v("(1996年に初期バージョンが公開 1998年に最初の公式API仕様が確立 2001年にStrutsが登場)")]),s._v(" "),t("p",[s._v("Java Servletの例")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("package")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("bootcamp")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("java"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("io"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("javax"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("servlet"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("javax"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("servlet"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("http"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloServlet")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("extends")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServlet")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")]),s._v(" doGet "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServletRequest")]),s._v(" req"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServletResponse")]),s._v(" res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("throws")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("ServletException")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("IOException")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("PrintWriter")]),s._v(" pw "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("getWriter")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("setContentType")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text/html; charset=Shift_JIS"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"

Welcome to IIJ Bootcamp

"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br")])]),t("p",[s._v("JavaのテンプレートエンジンであるJSP(JavaServer Pages)の例")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),s._v("@ page contentType"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text/html"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("html"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("head"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("title"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("IIJ "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Bootcamp")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("title"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("head"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("body"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("p"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("System")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("out"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("p"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n現在時刻"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("new")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("java"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("util"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),s._v("Date")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("body"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("html"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br")])]),t("ol",[t("li",[s._v("1995年Sun Microsystems社がJava言語を売り出した。\n"),t("ul",[t("li",[s._v("最初にアピールした"),t("code",[s._v("Applet")]),s._v("は、Webページの中にJavaのサンドボックス環境を埋め込んでアプリケーションを実行するというものだった。しかし制約が大きいうえにマシンパワーを要求するので、実用的なアプリケーションを作る環境としては、流行らなかった。")])])]),s._v(" "),t("li",[s._v("しかしサーバサイドの技術として発表されたサーブレットは2000年ごろから流行し始め、2001年にStrutsが登場するとその人気は決定的になった。\n"),t("ol",[t("li",[s._v("サーブレットはHTTPリクエストを(CGIのようにプロセスをforkするのではなく)スレッドで処理するので性能が高かった。")]),s._v(" "),t("li",[s._v("Javaは静的に型付けされた言語であるため、Javaで書かれたアプリケーションはPHPよりも品質を確保しやすいかった。")]),s._v(" "),t("li",[s._v("WebアプリケーションフレームワークであるStrutsを使うと、プログラムを一定のスタイルで記述することを助け、同時に大人数で分業することを助けた。規模の大きなエンタープライズシステムの実装が可能になった。")]),s._v(" "),t("li",[s._v("Javaで書かれたコードはポータビリティがあり、サーバのOSやCPUが変わっても、そのまま実行できた。(まだx86系のCPUが市場を独占しておらず、SPARCやAlphaなどのCPUもある程度のシェアを持っていた。)")])])]),s._v(" "),t("li",[s._v("かくしてカジュアルな(コンシューマ向けの)WebアプリケーションはPHPで、シリアスな(エンタープライズ向けの)WebアプリケーションはJavaサーブレットで書く、という時代が続くことになった。")])]),s._v(" "),t("h3",{attrs:{id:"java-ee-spring"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#java-ee-spring"}},[s._v("#")]),s._v(" Java EE / Spring")]),s._v(" "),t("p",[s._v("(Java EE 1999年 / Spring 2002年)")]),s._v(" "),t("p",[s._v("※ サンプルは適当です")]),s._v(" "),t("p",[s._v("JavaEE")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@ManagedBean")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"HelloBootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RequestScoped")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloBootcamp")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("private")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" message"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("/** Creates a new instance of HelloBootcamp */")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloBootcamp")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("this")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("message "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")]),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@EJB")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("private")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("MessageFacade")]),s._v(" messageFacade"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("getMessage")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("this")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("message"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br")])]),t("p",[s._v("Spring Framework")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RestController")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloController")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RequestMapping")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"/"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("index")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("ol",[t("li",[s._v("Sun Microsystemsはサーブレットの成功に気を良くして、これを一層強力に推進してエンタープライズの世界を支配しようと試みた。そうして出てきたのはJava EE(Enterprise Edition)であった。")]),s._v(" "),t("li",[s._v("Java EEは、エンタープライズアプリケーションを多数のサーバの連携する分散処理を通じて実現することを構想し、その中核技術としてEJB(Enterprise JavaBeans)を据えた。EJBを使うと、ネットワーク越しにJavaのオブジェクトが通信し合い、データベースへの永続化も含めてエレガントに処理できるはずだった。Sun Microsystemsの制定したJava EE仕様を実装するアプリケーションサーバ製品が複数のベンダーから出荷され、活況を呈した。")]),s._v(" "),t("li",[s._v("だが、実際のJava EEアプリケーションサーバ製品は不安定で性能も悪く、プログラミングも難しいものであった。人々はJava EEを信じて使い続けていたが、疑問も大きく膨らんでいった。")]),s._v(" "),t("li",[s._v("そこに登場したのがSpring Frameworkだった(2002年頃)。\n"),t("ul",[t("li",[s._v("作者のRod JohnsonがExpertt One-on-One J2EE Design and Developmentとともに世に問うたもの。")]),s._v(" "),t("li",[s._v("Java EE(J2EE) の欠点を指摘し、EJB、とりわけ"),t("code",[s._v("Entity Beans")]),s._v("を使うことは断念し、POJO(Plain Old Java Object) をベースに開発することを提唱した。")]),s._v(" "),t("li",[s._v("DI (Dependency Injecttion) のアイデアを普及させ、大規模なJavaアプリケーションを効率よく分業体制で実装する道を切り開いた。")])])]),s._v(" "),t("li",[s._v("Spring Frameworkは一世を風靡しただけでなく、今日まで人気を失うことなく、利用されている。\n"),t("ul",[t("li",[s._v("StrutsはStrus1の後継バージョンであるStruts2が、Struts1とまったく互換性がなかったため、Struts1を採用していた開発会社に受け入れられなかった。")]),s._v(" "),t("li",[s._v("その後脆弱性問題を連発したため、今日ではまったく人気がない。")])])])]),s._v(" "),t("h3",{attrs:{id:"ruby-on-rails"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ruby-on-rails"}},[s._v("#")]),s._v(" Ruby on Rails")]),s._v(" "),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloController")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" ApplicationController\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token method-definition"}},[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("hello")])]),s._v("\n render "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":html")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=>")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'

Welcom to IIJ Bootcamp

'")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token method-definition"}},[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("hello_json")])]),s._v("\n render "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":json")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=>")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("msg")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Welcom to IIJ Bootcamp'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br")])]),t("ol",[t("li",[s._v("2004年、37signals社がbasecampというプロジェクト管理アプリケーションの実装に使用していたRuby on RailsというWebアプリケーションフレームワークを発表した。Railsは非常にインパクトのあるフレームワークで、以降のサーバサイドプログラミングの世界を一変させてしまった。")]),s._v(" "),t("li",[s._v("その特徴を列挙すると以下のとおり。\n"),t("ol",[t("li",[s._v("2つの哲学。「同じことを繰り返さない DRY: Don't repeat yourself」「設定より規約 Convention over Configuration」\n"),t("ul",[t("li",[s._v("Strutsでは互いに関連し合う複雑な設定ファイルが多く必要だった\n"),t("ul",[t("li",[s._v("ルーティング(あるURLをどのアクションクラスで処理するかのマッピング)やアクションが処理するリクエストのフォームを記述するクラス、テンプレートの中で使用するタグライブラリの定義など")]),s._v(" "),t("li",[s._v("ほとんどの設定項目は、自動的なものであり、設定ファイルのメンテナンスは大量の単純作業であった。")])])]),s._v(" "),t("li",[s._v("そこで多くの現場ではExcelなどで主要設定項目を管理し、そのExcelファイルからマクロで個々の設定ファイルを生成するようなことが行われていた。")]),s._v(" "),t("li",[s._v("Railsでは、これを「デフォルトで定められているディレクトリ構造や命名規則に沿っている限り、設定ファイルは不要とする(特別な場合だけ、設定ファイルを書く)」という方法で解決した。")]),s._v(" "),t("li",[s._v("たとえばRDBMSのpersonsテーブルに対応するモデルクラスを、ModelsディレクトリにあるPerson.rbファイルとして記述すれば、自動的にDBアクセス可能とするというような具合である。")]),s._v(" "),t("li",[s._v("こうした開発者体験(Developer Experience)の良さは、Rubyが非常にメタプログラミングをしやすい言語であることで成り立っている。\n"),t("ul",[t("li",[s._v("Rails 独自の拡張や構文を多数実装することで、上記の哲学を実現している。")])])])])]),s._v(" "),t("li",[s._v("コマンドラインユーティリティによる開発のサポート\n"),t("ul",[t("li",[s._v("たとえばあるURLに対応するコントローラクラスのスケルトンをコマンドラインユーティリティから生成できる。")]),s._v(" "),t("li",[s._v("このようなユーティリティを提供することで、開発者を単純作業から解放し、価値あるコードを書くことへ集中できるようにした。")])])]),s._v(" "),t("li",[s._v("Ruby on Railsに触発されて、別の言語でも同様のフレームワークが多数開発された。\n"),t("ul",[t("li",[s._v("PHP: CakePHP")]),s._v(" "),t("li",[s._v("Java: JBoss Seam, Java EE 6, Grails(Groovyを使う)")]),s._v(" "),t("li",[s._v("Python: Django")])])])])]),s._v(" "),t("li",[s._v("今でも第一線で使われており、githubもRailsで作られ続けている。一方で一時期より採用されることは減ってきた。")])]),s._v(" "),t("ul",[t("li",[s._v("「マイクロサービス」が注目され、小さなアプリケーションを多く作るようになった\n"),t("ul",[t("li",[s._v("Railsはどちらかというと大きなアプリを作るためのフレームワークであり、マイクロサービスと対比してモノリスアプリの例として扱われる")]),s._v(" "),t("li",[s._v("とはいえ最近はまた一巡してモジュラーモノリスなど大きなアプリが着目されており、流れが変わりつつあるかもしれない")])])]),s._v(" "),t("li",[s._v("pythonが言語として人気であり、その流れでDjangoが採用されることが増えた(?)")]),s._v(" "),t("li",[s._v("Goなどに比べてパフォーマンス面で不利")])]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("rails generate controller User name:string email:string\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Person")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" ActiveRecord"),t("span",{pre:!0,attrs:{class:"token double-colon punctuation"}},[s._v("::")]),s._v("Base\n attr_accessible "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":email")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":name")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[s._v("person "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Person"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("find"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# id=1なデータをDBで検索する")]),s._v("\n\nPerson"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("create"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("email")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'hoge@example.com'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("username")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'hoge'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# データの作成(DBにinsert)")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("h3",{attrs:{id:"ajaxの出現-フロントエンド-apiサーバの時代"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ajaxの出現-フロントエンド-apiサーバの時代"}},[s._v("#")]),s._v(" Ajaxの出現 / フロントエンド+APIサーバの時代")]),s._v(" "),t("ol",[t("li",[s._v("Google MapsおよびGmailの出現により、「画面遷移を伴わないWebアプリケーション」というものがユーザーに認知され始めた。2005年ごろのことである。")]),s._v(" "),t("li",[s._v("Googleのエンジニアたちの使った技法は、技術としてはそれ以前から存在していたが誰も注目してこなかったXMLHttpRequestというJavaScriptの機能を初めて本格的に使用するものだった。\n"),t("ol",[t("li",[s._v("この技法をAsynchronous JavaScript + XMLの頭文字をとってAjax (エイジャックス) と呼ぶようになった。")])])]),s._v(" "),t("li",[s._v("StrutsやRuby on Railsはサーバサイド(バックエンド)側でリクエストを処理して画面も生成するというようなスタイルが中心だった。しかしAjaxが人気を集めるようになるとクライアント(フロントエンド)側で画面描画をすべて行い、バックエンドにはAPIサーバのみを置くというスタイルが人気を集めるようになった。\n"),t("ol",[t("li",[s._v("画面遷移を伴わないWebアプリケーションのことをSPA (Single Page Application) などと呼ぶ。")]),s._v(" "),t("li",[s._v("このスタイルが定着すると、デスクトップアプリケーションと比較しても遜色ないUIのWebアプリケーションが当たり前のように期待されるようになっていった。")]),s._v(" "),t("li",[s._v("要求の高度化に応えるため、フロントエンド側のフレームワークが非常に速いペースで開発されているのが今日の状況である。今日、人気のあるフロントエンド・フレームワークとしてReact (Facebook)、Angular (Google)、Vue.js (Evan You)などがある。")])])])]),s._v(" "),t("h3",{attrs:{id:"node-js"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#node-js"}},[s._v("#")]),s._v(" Node.js")]),s._v(" "),t("p",[s._v("Perlから始まり、ここまで出てきたJavaやRailsは基本的に同期的なI/Oとシングルプロセスで動作する。\nそのため複数のリクエストを同時に処理するためにはマルチプロセスやスレッドといった仕組みを利用する必要があった。")]),s._v(" "),t("ul",[t("li",[s._v("マルチプロセス: リクエストごと、あるいは事前にプロセスを複数立ち上げておき、1つのリクエストを1プロセスに割り当てる\n"),t("ul",[t("li",[s._v("CGI, FastCGI, Railsのpassengerなど。Apache自体も長らくこの仕組みだった")])])]),s._v(" "),t("li",[s._v("スレッド: 言語内で並列処理用の軽量なプロセスを立ち上げる。負荷は低いが言語ごとに癖がある\n"),t("ul",[t("li",[s._v("Javaなど")])])]),s._v(" "),t("li",[s._v("上の二つは組み合わせて利用する場合もある")])]),s._v(" "),t("p",[t("img",{attrs:{src:a(467),alt:"apache_railes",title:"apache_railes"}})]),s._v(" "),t("p",[s._v("しかしインターネット利用者に増加にともなってWebサービスへのアクセス量も増え、プロセスのforkやスレッドによる処理モデルの限界が表面化してきた。特にプロセスの場合は1サーバあたりで起動できるプロセス数には限界がある他、プロセスを作るコスト(メモリ消費など)が無視できなくなってきたのである。\n(C10K問題と呼ばれる)")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),t("p",[s._v("たとえば32bit環境のlinuxサーバでは、プロセスの作成上限は管理番号(PID)の上限となる32768になる。\nまた1スレッドあたり数MBのメモリを使うとすると、8GBのメモリを積んだサーバでは4000ほどが上限になる。\n(あくまで単純に計算した場合の理論値)")])]),s._v(" "),t("p",[s._v("この問題への解決として、Node.jsをはじめとした非同期I/OとEventDrivenなアーキテクチャが注目された。\nNode.jsはJavaScriptの実行環境の一つで、I/O待ち(HDDへの書き込みなど)中に他の処理を行うことで、1プロセスで複数のリクエストを同時に処理することができる。")]),s._v(" "),t("p",[s._v("Node.jsのイベントループによる非同期I/Oの実現")]),s._v(" "),t("p",[t("img",{attrs:{src:a(468),alt:"event-loop",title:"event-loop"}})]),s._v(" "),t("p",[s._v("Node.jsの中でリクエストを並列に捌けるためWebアプリ用にプロセスをforkする必要がなくなり、裏で動いているNode.jsのサーバにリクエストをただプロキシするだけで良くなった。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(469),alt:"node",title:"node"}})]),s._v(" "),t("p",[s._v("開発スタイルの特徴としては以下が挙げられる。")]),s._v(" "),t("ul",[t("li",[s._v("フロントエンド開発と同じJavaScriptで書けるので、1サービスを作るのに複数の言語を扱わなくてよくなる")]),s._v(" "),t("li",[s._v("豊富なライブラリやツールの選択肢がある")]),s._v(" "),t("li",[s._v("反面EventDrivenな実装はコードが複雑になりがちで、どちらかというと小規模な実装向け\n"),t("ul",[t("li",[s._v("TypeScriptによる型の導入やasync/await記法の導入などで改善されつつはある")])])]),s._v(" "),t("li",[s._v("できるだけ自分で実装せずにライブラリを使うことがよしとされる風潮があり、ライブラリの依存関係が膨らみがち\n"),t("ul",[t("li",[s._v("正しくはあるが、小さな機能のために追加ライブラリをパッケージする必要があり、依存関係の複雑さやビルド時間の増加を招く")]),s._v(" "),t("li",[s._v("Rubyの頃からある業界的な課題ではあるが、Node.jsでは特に顕著")])])])]),s._v(" "),t("p",[s._v("最近ではSPAフレームワークからの流れでSSR(Server Side Rendering)を採用するサービスも増えており、その実行環境としてNode.jsが引き続き使われている。")]),s._v(" "),t("p",[s._v("最近は "),t("a",{attrs:{href:"https://deno.land/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Deno"),t("OutboundLink")],1),s._v(" というTypeScriptがネイティブで動作するランタイムも流行り始めている。")]),s._v(" "),t("h3",{attrs:{id:"go言語"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#go言語"}},[s._v("#")]),s._v(" Go言語")]),s._v(" "),t("p",[s._v("2016年くらいから利用例の増えてきたプログラミング言語で、静的型付け・シンプルな言語体系・高速な動作・並行処理が得意などの特徴がある。\nRubyやPythonなどのスクリプト言語のような開発スピードと、JavaやCのような静的型付けによる安全性・実行の速さを両立していることで、Webサービスのバックエンドとして使われることが増えた。\nRubyやPython、Javaなどのように実行環境をインストールする必要がなく、コンパイルしたバイナリファイル1つで動作するため、デプロイや環境構築が容易なのも特徴。\nまたGoにはgoroutineという軽量なスレッドのような並行処理の仕組みがあり、このgoroutineを使って複数のリクエストを処理することができる。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(470),alt:"go",title:"go"}})]),s._v(" "),t("p",[s._v("開発スタイルとしては以下のような特徴がある。")]),s._v(" "),t("ul",[t("li",[s._v("あまりライブラリやフレームワークを使わずに、自分で実装することが推奨される\n"),t("ul",[t("li",[s._v("標準ライブラリが優秀で、大抵の機能はフレームワークがなくても十分実装できる")]),s._v(" "),t("li",[s._v("抽象化関連の機能も少ないためフレームワークの旨味があまりなく、デファクトが生まれづらい")])])]),s._v(" "),t("li",[s._v("goroutineという仕組みでシンプルに並行処理が書ける")]),s._v(" "),t("li",[s._v("言語仕様がシンプルなのと静的型付けなこともあり、linterやコード補完ツールが作りやすい\n"),t("ul",[t("li",[s._v("言語解析をしてくれる"),t("code",[s._v("analysis package")]),s._v("が公式から提供されている")])])]),s._v(" "),t("li",[s._v("コーディング規約がある程度公式で決まっており、誰が書いても同じ書き方になる\n"),t("ul",[t("li",[s._v("複数人での開発がやりやすい")])])]),s._v(" "),t("li",[s._v("コンパイル言語なので(スクリプト言語に比べると)デバッグが難しい")]),s._v(" "),t("li",[s._v("Railsのようなフレームワークに頼らず、自力でアプリケーションを構築していく必要がある")])]),s._v(" "),t("h3",{attrs:{id:"その先"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#その先"}},[s._v("#")]),s._v(" その先...")]),s._v(" "),t("ul",[t("li",[s._v("Haskellなどの関数型言語が流行りそう?")]),s._v(" "),t("li",[s._v("Rustはいい言語だが書くのが難しく、どちらかというとOSなどのシステムプログラミング向け\n"),t("ul",[t("li",[s._v("Rustのメモリ管理はGC(ガベージコレクト)を起こさないためのもの")]),s._v(" "),t("li",[s._v("Webアプリの実行環境はある程度メモリやCPUを富豪的に使えるため、書きやすさを優先してGoやRuby, JavaなどGCのある言語が使われる傾向にある")])])])]),s._v(" "),t("h2",{attrs:{id:"アプリケーションプログラミングインタフェース-api-の色々"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#アプリケーションプログラミングインタフェース-api-の色々"}},[s._v("#")]),s._v(" アプリケーションプログラミングインタフェース(API) の色々")]),s._v(" "),t("p",[s._v("API(Application Programming Interface)とはアプリケーションが他のソフトウェアの機能を利用するための仕組みを指す。\nWebアプリケーションの文脈では主にhttpプロトコル越しに他のWebアプリケーションにrequestを送信し、responseを受け取る仕組みを指す。")]),s._v(" "),t("p",[s._v("一番分かりやすいのはブラウザ上で動作するJavaScriptがサーバのAPIを叩いてJSON形式のresponseを受け取るもの。\n他に実は裏側でサーバ同士がAPIでやり取りしていることもよくあるし、サーバからさらに外部のサービスを呼び出す場合もある。")]),s._v(" "),t("p",[s._v("APIをどのような形式で実装するかは非常に重要な問題で、過去から現在に至るまで様々な設計・実装手法が存在しています。\nプログラミング言語と同様に長い変遷の歴史があるので、そちらを紹介していこうと思います。")]),s._v(" "),t("h3",{attrs:{id:"rpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rpc"}},[s._v("#")]),s._v(" RPC")]),s._v(" "),t("p",[s._v("そもそもプログラムからネットワーク越しに外部のプログラムの機能を実行する仕組みをRPC(Remote Procedure Call)と呼びます。\n黎明期におけるRPCはHTTPなどのWebの仕組みは前提にしておらず、各言語や実装ごとに独自の仕組みで動作するものでした。")]),s._v(" "),t("p",[s._v("その根底には「遠隔地(remote)で動いているプログラムの関数を実行する」という思想があり、RPC系のAPIは関数名と引数を指定してレスポンスを受け取るというイメージで使われます。")]),s._v(" "),t("h3",{attrs:{id:"xml-rpc-json-rpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#xml-rpc-json-rpc"}},[s._v("#")]),s._v(" XML/RPC(JSON-RPC)")]),s._v(" "),t("p",[s._v("独自の仕組みで動いていたRPCをHTTP通信を前提にして規格として整えたものはXML/RPCと呼ばれる。\n字の如くXML形式のデータをやり取りし、そのフォーマットなどを定めたものなっている。")]),s._v(" "),t("p",[s._v("リクエストの例")]),s._v(" "),t("div",{staticClass:"language-xml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-xml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token prolog"}},[s._v('')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodCall")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodName")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("examples.getStateName"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("params")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("param")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("i4")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("40"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("p",[s._v("レスポンスの例")]),s._v(" "),t("div",{staticClass:"language-xml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-xml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token prolog"}},[s._v('')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodResponse")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("params")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("param")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("string")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("South Dakota"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br")])]),t("p",[s._v("XMLの代わりにJSON形式でやり取りされる場合はJSON-RPCと呼ばれる。")]),s._v(" "),t("h3",{attrs:{id:"soap"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#soap"}},[s._v("#")]),s._v(" SOAP")]),s._v(" "),t("p",[s._v("XML/RPCを発展させたもの?\n主にエンタープライズの文脈で企業同士がデータのやり取りをするために利用されていたらしい。")]),s._v(" "),t("p",[s._v("(よく知らないので誰か追記してください)")]),s._v(" "),t("h3",{attrs:{id:"rest"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rest"}},[s._v("#")]),s._v(" REST")]),s._v(" "),t("p",[s._v("RPCは相手がどのようなメソッド(関数)を実装しているのか、そのメソッドがどのような挙動をするのか定まっておらず、統一感がなかった。\nそこで「APIの設計思想」のようなものとしてRESTが登場し、そのRESTの思想を満たすようなAPIをRESTful APIと呼ぶ。")]),s._v(" "),t("p",[s._v("その原則には以下のような項目が挙げられる。")]),s._v(" "),t("ul",[t("li",[s._v("リソースをURLを通して表現すること\n"),t("ul",[t("li",[s._v("例えば "),t("code",[s._v("example.com/book/001")]),s._v(" は「"),t("code",[s._v("001")]),s._v("というIDが付けられた"),t("code",[s._v("book")]),s._v("」というリソースを表す")])])]),s._v(" "),t("li",[s._v("セッションなどの状態管理を行わないこと(=ステートレス性)")]),s._v(" "),t("li",[s._v("HTTPにおける GET/POST/PUT/DELETE の各メソッドをそのままリソースの 取得/作成/編集/削除 に対応させる\n"),t("ul",[t("li",[t("code",[s._v("GET example.com/book/")]),s._v(" をするとbookの一覧が取得できる")]),s._v(" "),t("li",[t("code",[s._v("POST example.com/book/")]),s._v(" で新しいbookを追加する")]),s._v(" "),t("li",[t("code",[s._v("GET example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookの詳細を取得する")]),s._v(" "),t("li",[t("code",[s._v("PUT example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookを更新する")]),s._v(" "),t("li",[t("code",[s._v("DELETE example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookを削除する")])])])]),s._v(" "),t("p",[s._v("とはいえ厳密にRESTに従っているものは少なく、多少違反していてもざっくり「REST API」と呼ばれることが多い。\n(なんちゃってRESTとか言ったりする)")]),s._v(" "),t("p",[s._v("元々は「到達可能性」のような概念が謳われており、例えば"),t("code",[s._v("GET")]),s._v("で取得した内容に他のリソースのURLが含まれることで、人間がブラウザを使うのと同じように機械が情報を自律的に探索可能にすることも目指されていた。\nその未来は来ず、世の中にはなんちゃってRESTが便利に使われている。")]),s._v(" "),t("p",[s._v("データフォーマットには基本的にJSONが使われる。")]),s._v(" "),t("h3",{attrs:{id:"openapi"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#openapi"}},[s._v("#")]),s._v(" OpenAPI")]),s._v(" "),t("p",[s._v("REST APIの仕様を機械可読可能な形で記述するための仕様。\n元々「Swagger」という名前だったのが、汎用的な仕様として定義するにあたって「OpenAPI」と名前が付けられた。")]),s._v(" "),t("p",[s._v("以下はymlで書かれたAPI仕様の例")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("openapi")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" 3.0.3\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("info")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("title")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp example\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("|")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("\n This is a sample Pet Store Server.\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("version")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"1.0"')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("paths")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("/pet")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("post")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("tags")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" pet\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("summary")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Add a new pet to the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Add a new pet to the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("requestBody")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Create a new pet in the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("responses")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'200'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Successful operation\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v(" \n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'405'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Invalid input\n /pet/"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("petId"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("get")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("summary")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Find pet by ID\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Returns a single pet\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("parameters")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" petId\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("in")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" path\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ID of pet to return\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" integer\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("format")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" int64\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("responses")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'200'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" successful operation\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'400'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Invalid ID supplied\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'404'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Pet not found\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("components")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schemas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("Pet")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" name\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" photoUrls\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" object\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("properties")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("id")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" integer\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("format")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" int64\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("example")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" string\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("example")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" doggie\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br"),t("span",{staticClass:"line-number"},[s._v("46")]),t("br"),t("span",{staticClass:"line-number"},[s._v("47")]),t("br"),t("span",{staticClass:"line-number"},[s._v("48")]),t("br"),t("span",{staticClass:"line-number"},[s._v("49")]),t("br"),t("span",{staticClass:"line-number"},[s._v("50")]),t("br"),t("span",{staticClass:"line-number"},[s._v("51")]),t("br"),t("span",{staticClass:"line-number"},[s._v("52")]),t("br"),t("span",{staticClass:"line-number"},[s._v("53")]),t("br"),t("span",{staticClass:"line-number"},[s._v("54")]),t("br"),t("span",{staticClass:"line-number"},[s._v("55")]),t("br"),t("span",{staticClass:"line-number"},[s._v("56")]),t("br"),t("span",{staticClass:"line-number"},[s._v("57")]),t("br"),t("span",{staticClass:"line-number"},[s._v("58")]),t("br"),t("span",{staticClass:"line-number"},[s._v("59")]),t("br"),t("span",{staticClass:"line-number"},[s._v("60")]),t("br"),t("span",{staticClass:"line-number"},[s._v("61")]),t("br"),t("span",{staticClass:"line-number"},[s._v("62")]),t("br"),t("span",{staticClass:"line-number"},[s._v("63")]),t("br"),t("span",{staticClass:"line-number"},[s._v("64")]),t("br"),t("span",{staticClass:"line-number"},[s._v("65")]),t("br"),t("span",{staticClass:"line-number"},[s._v("66")]),t("br"),t("span",{staticClass:"line-number"},[s._v("67")]),t("br")])]),t("p",[s._v("仕様に従って書かれているので、これを画面で作成するのも簡単ですし、綺麗に整形することもできます。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(471),alt:"",title:"open_api_1"}})]),s._v(" "),t("p",[t("img",{attrs:{src:a(472),alt:"",title:"open_api_2"}})]),s._v(" "),t("p",[t("a",{attrs:{href:"https://editor.swagger.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://editor.swagger.io/"),t("OutboundLink")],1),s._v(" で触れるのでぜひ試してみてください。")]),s._v(" "),t("p",[s._v("APIを作る場合必ず仕様書を用意しますが、open_apiのフォーマットに従うと何を書くべきなのか明確ですし、そこから綺麗な形式に出力することができます。\nまたopen_apiの仕様からコードを自動生成するツールも多数存在しており、REST APIを設計する場合、可能な限りopen_apiで仕様を定義しておくと後々役に立ちます。")]),s._v(" "),t("h3",{attrs:{id:"graphql"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#graphql"}},[s._v("#")]),s._v(" GraphQL")]),s._v(" "),t("p",[s._v("RESTに代表されるように、データへのアクセス方法や形式(レスポンスのJSON構造など)はサーバ側が決め、クライアントはその定義に従ってAPIを叩くのが基本でした。\nしかしモバイルアプリによる利用が増える中で、ブラウザからのアクセスとモバイルアプリからのアクセスで異なるデータ形式が望ましいケースが出てきました。\nこういったユースケースに対応するため、APIで取得するデータ形式をクライアント側で指定できるのがGraphQLです。")]),s._v(" "),t("p",[s._v("単純な例では、例えばREST APIで"),t("code",[s._v("GET https://example.com/persons")]),s._v("すると以下のようなデータが返ってきたとします。")]),s._v(" "),t("div",{staticClass:"language-json line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-json"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group_id"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"profile"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque nisl eros, pulvinar facilisis."')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group_id"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"profile"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero."')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n ...\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br")])]),t("p",[s._v("ここでモバイルアプリは"),t("code",[s._v("profile")]),s._v("が不要な一方、"),t("code",[s._v("group")]),s._v("の情報も一緒にUIに出したいとします。\nその場合"),t("code",[s._v("profile")]),s._v("の長いデータは完全に無駄な通信ですし、"),t("code",[s._v("group")]),s._v("の情報を問い合わせるために"),t("code",[s._v("GET https://example.com/groups/5")]),s._v("をしないといけません。モバイルアプリにとって理想的なAPIにするためには、サーバ側に新しいAPIを作ってもらう必要があります。")]),s._v(" "),t("p",[s._v("これをクライアント側で制御するのがGraphQLのやりたいことで、例えばGraphQLでは以下のようなクエリをサーバの"),t("code",[s._v("https://example.com/graphql")]),s._v("にPOSTします。")]),s._v(" "),t("div",{staticClass:"language-graphql line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-graphql"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("query")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token object"}},[s._v("persons")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("name")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("email")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token object"}},[s._v("group")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("name")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("p",[s._v("するとサーバが以下のようなレスポンスを返してくるという算段です。")]),s._v(" "),t("div",{staticClass:"language-json line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-json"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"data"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"persons"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Engineering Team"')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Marketing Team"')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n ...\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br")])]),t("p",[s._v("様々なユースケースを持つクライアントが多く存在するような場合非常に強力です。"),t("a",{attrs:{href:"https://docs.github.com/ja/graphql",target:"_blank",rel:"noopener noreferrer"}},[s._v("githubのAPI"),t("OutboundLink")],1),s._v(" は多数向けに公開されデータ構造も複雑なため、まさにgraphqlがハマるパターンです。")]),s._v(" "),t("p",[s._v("一方でgraphqlとしては一発でデータを取れているように見えても、データベース上は相変わらずperson -> groupとSQLを2回以上叩く必要があるかもしれません。\nクライアント側のユースケースが限られサーバ側の実装変更が可能であれば、ユースケースに合わせて効率よくデータを取得できるAPIを作った方がパフォーマンストラブルを引き起こさずに済むでしょう。")]),s._v(" "),t("h3",{attrs:{id:"grpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#grpc"}},[s._v("#")]),s._v(" gRPC")]),s._v(" "),t("p",[s._v("gRPCは名前の通りRPC(Remote Procedure Call)を実現するためのプロトコルです。\nAPIを "),t("a",{attrs:{href:"https://protobuf.dev/overview/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Protocol Buffers"),t("OutboundLink")],1),s._v(" という形式で定義し、そのprotoファイルを元に各言語用のコードを生成することで、同じAPI定義を異なる言語で共有することが容易にできます。\ntransport層としてhttp2を前提にしており、単純なrequest-responseだけではなく双方向のstreamingもサポートしています。\nまた実際にやり取りされるデータは最小限のバイナリになっており、jsonに比べて低容量に通信ができます。")]),s._v(" "),t("p",[s._v("以下はprotoファイルの例です")]),s._v(" "),t("div",{staticClass:"language-proto line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("// GetPersonRequest を受け取って GetPersonResponse を返すメソッドの定義\nservice Person {\n rpc GetPerson (GetPersonRequest) returns (GetPersonResponse) {}\n}\n\n// GetPersonsRequest のリクエスト定義\nmessage GetPersonsRequest {\n string name = 1;\n}\n\n// HelloReply のレスポンス定義\nmessage GetPersonResponse {\n Person person = 1;\n\n message Person {\n string name = 1;\n string email = 2;\n string profile = 3;\n }\n}\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br")])]),t("p",[s._v("このproto定義から各言語向けに型定義を含めたコードを生成するため、実装が自由なOpenAPIに比べるとより厳密にAPIを実装できます。")]),s._v(" "),t("credit-footer")],1)}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{461:function(s,t,a){s.exports=a.p+"assets/img/web_app_true1.drawio.c12026f8.png"},462:function(s,t,a){s.exports=a.p+"assets/img/web_app_true2.drawio.d698dacd.png"},463:function(s,t){s.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI0AAAD9CAYAAACBfPRkAAAAAXNSR0IArs4c6QAACPF0RVh0bXhmaWxlACUzQ214ZmlsZSUzRSUzQ2RpYWdyYW0lMjBpZCUzRCUyMmRZdWtSSjdiVUNwY1NTaXVMdmlEJTIyJTIwbmFtZSUzRCUyMiVFMyU4MyU5QSVFMyU4MyVCQyVFMyU4MiVCODElMjIlM0UlM0NteEdyYXBoTW9kZWwlMjBkeCUzRCUyMjcxOSUyMiUyMGR5JTNEJTIyMTA0OSUyMiUyMGdyaWQlM0QlMjIxJTIyJTIwZ3JpZFNpemUlM0QlMjIxMCUyMiUyMGd1aWRlcyUzRCUyMjElMjIlMjB0b29sdGlwcyUzRCUyMjElMjIlMjBjb25uZWN0JTNEJTIyMSUyMiUyMGFycm93cyUzRCUyMjElMjIlMjBmb2xkJTNEJTIyMSUyMiUyMHBhZ2UlM0QlMjIxJTIyJTIwcGFnZVNjYWxlJTNEJTIyMSUyMiUyMHBhZ2VXaWR0aCUzRCUyMjgyNyUyMiUyMHBhZ2VIZWlnaHQlM0QlMjIxMTY5JTIyJTIwYmFja2dyb3VuZCUzRCUyMiUyM2ZmZmZmZiUyMiUyMG1hdGglM0QlMjIwJTIyJTIwc2hhZG93JTNEJTIyMCUyMiUzRSUzQ3Jvb3QlM0UlM0NteENlbGwlMjBpZCUzRCUyMjAlMjIlMkYlM0UlM0NteENlbGwlMjBpZCUzRCUyMjElMjIlMjBwYXJlbnQlM0QlMjIwJTIyJTJGJTNFJTNDbXhDZWxsJTIwaWQlM0QlMjIxMSUyMiUyMHZhbHVlJTNEJTIyJUUzJTgyJUI1JUUzJTgyJUE0JUUzJTgzJTg4JUU5JTk2JUIyJUU4JUE2JUE3JTIyJTIwc3R5bGUlM0QlMjJlZGdlU3R5bGUlM0Rub25lJTNCaHRtbCUzRDElM0JleGl0WCUzRDAuMjUlM0JleGl0WSUzRDAlM0JleGl0RHglM0QwJTNCZXhpdER5JTNEMCUzQmVudHJ5WCUzRDAuMjUlM0JlbnRyeVklM0QxJTNCZW50cnlEeCUzRDAlM0JlbnRyeUR5JTNEMCUzQiUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjBzb3VyY2UlM0QlMjI1JTIyJTIwdGFyZ2V0JTNEJTIyMTQlMjIlMjBlZGdlJTNEJTIyMSUyMiUzRSUzQ214R2VvbWV0cnklMjByZWxhdGl2ZSUzRCUyMjElMjIlMjBhcyUzRCUyMmdlb21ldHJ5JTIyJTJGJTNFJTNDJTJGbXhDZWxsJTNFJTNDbXhDZWxsJTIwaWQlM0QlMjI1JTIyJTIwdmFsdWUlM0QlMjJXZWIlRTMlODMlOTYlRTMlODMlQTklRTMlODIlQTYlRTMlODIlQjYlMjIlMjBzdHlsZSUzRCUyMnJvdW5kZWQlM0QwJTNCd2hpdGVTcGFjZSUzRHdyYXAlM0JodG1sJTNEMSUzQiUyMiUyMHBhcmVudCUzRCUyMjElMjIlMjB2ZXJ0ZXglM0QlMjIxJTIyJTNFJTNDbXhHZW9tZXRyeSUyMHglM0QlMjI0MCUyMiUyMHklM0QlMjIxOTAlMjIlMjB3aWR0aCUzRCUyMjEyMCUyMiUyMGhlaWdodCUzRCUyMjYwJTIyJTIwYXMlM0QlMjJnZW9tZXRyeSUyMiUyRiUzRSUzQyUyRm14Q2VsbCUzRSUzQ214Q2VsbCUyMGlkJTNEJTIyMTMlMjIlMjB2YWx1ZSUzRCUyMkhUTUwlMjIlMjBzdHlsZSUzRCUyMmVkZ2VTdHlsZSUzRG5vbmUlM0JodG1sJTNEMSUzQmV4aXRYJTNEMC43NSUzQmV4aXRZJTNEMSUzQmV4aXREeCUzRDAlM0JleGl0RHklM0QwJTNCZW50cnlYJTNEMC43NSUzQmVudHJ5WSUzRDAlM0JlbnRyeUR4JTNEMCUzQmVudHJ5RHklM0QwJTNCJTIyJTIwcGFyZW50JTNEJTIyMSUyMiUyMHNvdXJjZSUzRCUyMjE0JTIyJTIwdGFyZ2V0JTNEJTIyNSUyMiUyMGVkZ2UlM0QlMjIxJTIyJTNFJTNDbXhHZW9tZXRyeSUyMHJlbGF0aXZlJTNEJTIyMSUyMiUyMGFzJTNEJTIyZ2VvbWV0cnklMjIlMkYlM0UlM0MlMkZteENlbGwlM0UlM0NteENlbGwlMjBpZCUzRCUyMjIlMjIlMjB2YWx1ZSUzRCUyMkFjdG9yJTIyJTIwc3R5bGUlM0QlMjJzaGFwZSUzRHVtbEFjdG9yJTNCdmVydGljYWxMYWJlbFBvc2l0aW9uJTNEYm90dG9tJTNCdmVydGljYWxBbGlnbiUzRHRvcCUzQmh0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"},464:function(s,t,a){s.exports=a.p+"assets/img/web_app_true3.drawio.45cb353d.png"},465:function(s,t,a){s.exports=a.p+"assets/img/perl_cgi.drawio.c9857297.png"},466:function(s,t,a){s.exports=a.p+"assets/img/mod_perl.drawio.80a12876.png"},467:function(s,t,a){s.exports=a.p+"assets/img/apache_rails.drawio.7dadfe95.png"},468:function(s,t,a){s.exports=a.p+"assets/img/event-loop.08b77931.png"},469:function(s,t,a){s.exports=a.p+"assets/img/node.drawio.0548a511.png"},470:function(s,t,a){s.exports=a.p+"assets/img/go.drawio.c70b0a4e.png"},471:function(s,t,a){s.exports=a.p+"assets/img/open_api_1.fde7ab4c.png"},472:function(s,t,a){s.exports=a.p+"assets/img/open_api_2.5bbd593d.png"},541:function(s,t,a){"use strict";a.r(t);var n=a(10),e=Object(n.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"サーバアプリケーション界隈overview"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#サーバアプリケーション界隈overview"}},[s._v("#")]),s._v(" サーバアプリケーション界隈Overview")]),s._v(" "),t("h2",{attrs:{id:"webアプリケーションとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#webアプリケーションとは"}},[s._v("#")]),s._v(" Webアプリケーションとは?")]),s._v(" "),t("p",[s._v("世の中はWebアプリケーションで溢れています。")]),s._v(" "),t("p",[s._v("この図の「Ruby on Rails」と書かれているのはWebアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(461),alt:"web_app_true1.png",title:"web_app_true1"}})]),s._v(" "),t("p",[s._v("次の図の「Perl CGI」もWebアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(462),alt:"web_app_true2.png",title:"web_app_true2"}})]),s._v(" "),t("p",[s._v("次の図の「Apache」はWebアプリケーションじゃない。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(463),alt:"web_app_false1.png",title:"web_app_false1"}})]),s._v(" "),t("p",[s._v("次の図の「Go」は多分Webアプリケーション。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(464),alt:"web_app_true3.png",title:"web_app_true3"}})]),s._v(" "),t("p",[s._v("明確な定義はありませんが、サーバ上で動作しHTTPなどの仕組みを利用してWeb上からアクセスされること、DBなどと連携し何らかの動的な結果を返すアプリケーションのことを呼びます。")]),s._v(" "),t("h2",{attrs:{id:"色々なwebアプリケーションの実装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#色々なwebアプリケーションの実装"}},[s._v("#")]),s._v(" 色々なWebアプリケーションの実装")]),s._v(" "),t("p",[s._v("Webアプリケーションはwebの発展と共に様々な「書き方」と「動かし方」が提案されていました。\n書き方が同じでも動かし方が変わったもの、言語を含めて書き方だけが違うやり方、様々です。")]),s._v(" "),t("p",[s._v("この章では様々なWebアプリケーションの実装を「書き方」と「動かし方」それぞれの面で見ていきます。\n大体登場した歴史順に紹介しますが、必ずしも新しいものが正しい・素晴らしいというわけではなく、「得意なユースケースは何か?」がポイントとなります。")]),s._v(" "),t("h3",{attrs:{id:"cgi"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#cgi"}},[s._v("#")]),s._v(" CGI")]),s._v(" "),t("p",[s._v("(1993年 フォーマルな"),t("a",{attrs:{href:"https://www.w3.org/CGI/",target:"_blank",rel:"noopener noreferrer"}},[s._v("仕様"),t("OutboundLink")],1),s._v("制定は1997年)")]),s._v(" "),t("div",{staticClass:"language-perl line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-perl"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#!/usr/bin/perl")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Content-type: text/html \\n\\n"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"

Welcome to IIJ Bootcamp

"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("print")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("ul",[t("li",[s._v("Common Gateway Interface の略")]),s._v(" "),t("li",[s._v('The Apache HTTP Server ("httpd") などのWebサーバでHTTPリクエストを受けて、外部プログラムにHTTPリクエストを渡し、出力をHTTPレスポンスとして返すしくみ。')]),s._v(" "),t("li",[s._v("Perlが大流行するきっかけとなった。\n"),t("ul",[t("li",[s._v("Perlは文字列処理が強力(C言語は文字列処理が貧弱)")]),s._v(" "),t("li",[s._v("PerlからMySQL/PostgreSQLに接続してHTTPレスポンスを生成するスタイル")])])]),s._v(" "),t("li",[s._v("今日でもPerlで実装されたプロダクトは存続している(MovableTypeとか、mixiとか。CookPadもPerlでスタートしたはず)。")]),s._v(" "),t("li",[s._v("CGIの仕組み自体はPerl以外でもRubyやPython、シェルスクリプトなど文字列を出力できるプログラムであれば利用できる")])]),s._v(" "),t("p",[s._v("CGIはHTTPリクエストを受けるごとに、新しいプロセスをforkする必要があり、Webサーバにとって負荷が高かった。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(465),alt:"perl_cgi",title:"perl_cgi"}})]),s._v(" "),t("p",[s._v("WebサーバのモジュールとしてPerlを動作させる「mod_perl」という方法が考案された(apache httpd + mod_perl 1998年)")]),s._v(" "),t("p",[t("img",{attrs:{src:a(466),alt:"mod_perl",title:"mod_perl"}})]),s._v(" "),t("h3",{attrs:{id:"php"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#php"}},[s._v("#")]),s._v(" PHP")]),s._v(" "),t("div",{staticClass:"language-php line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-php"}},[t("code",[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("html")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("head")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("title")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("IIJ Bootcamp"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("body")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token php language-php"}},[t("span",{pre:!0,attrs:{class:"token delimiter important"}},[s._v("Welcom to IIJ Bootcamp

'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token delimiter important"}},[s._v("?>")])]),s._v(" \n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br")])]),t("p",[s._v("(開発開始は1994年 実質的に最初の公開版PHP 3が1997年 本格普及はPHP 4で2000年)")]),s._v(" "),t("ol",[t("li",[s._v("CGIはHTTPリクエストを受けるごとに、新しいプロセスをforkする必要があり、Webサーバにとって負荷が高かった。")]),s._v(" "),t("li",[s._v("前述の通りmod_perlという形でPerlを動作させる手法が流行っていた")]),s._v(" "),t("li",[s._v("しかし当然ながらPerlはWebサーバのモジュールとして動作させる前提で設計・実装されたものではなく、使い勝手が悪かった")]),s._v(" "),t("li",[s._v("類似の技術としてFastCGIというものもあったが、やはり癖があり使いにくかった")]),s._v(" "),t("li",[s._v("そこで最初からWebサーバのモジュールとして実行することを念頭に置いた、Webプログラミングに特化した処理系としてPHPが登場、大流行してPerlを駆逐する。\n"),t("ol",[t("li",[s._v("Facebookも長い間PHPで書かれていた。")])])]),s._v(" "),t("li",[s._v("元々はWebページを動的に生成するためのテンプレート的な言語であったが、機能が追加された結果スクリプト言語としての機能も持つ")]),s._v(" "),t("li",[s._v("動かし方はCGI, mod_php(モジュール形式)などがあり、Perlの項目とほぼ同様の形式で動作する")]),s._v(" "),t("li",[s._v("現在でも広く利用されており、"),t("a",{attrs:{href:"https://cakephp.org/jp",target:"_blank",rel:"noopener noreferrer"}},[s._v("CakePHP"),t("OutboundLink")],1),s._v(" など今風のフレームワークも存在する")])]),s._v(" "),t("h3",{attrs:{id:"java-servlet-サーブレット"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#java-servlet-サーブレット"}},[s._v("#")]),s._v(" Java Servlet (サーブレット)")]),s._v(" "),t("p",[s._v("(1996年に初期バージョンが公開 1998年に最初の公式API仕様が確立 2001年にStrutsが登場)")]),s._v(" "),t("p",[s._v("Java Servletの例")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("package")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("bootcamp")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("java"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("io"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("javax"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("servlet"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token import"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("javax"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("servlet"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("http"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloServlet")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("extends")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServlet")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("void")]),s._v(" doGet "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServletRequest")]),s._v(" req"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HttpServletResponse")]),s._v(" res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("throws")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("ServletException")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("IOException")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("PrintWriter")]),s._v(" pw "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("getWriter")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n res"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("setContentType")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text/html; charset=Shift_JIS"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"

Welcome to IIJ Bootcamp

"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n pw"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br")])]),t("p",[s._v("JavaのテンプレートエンジンであるJSP(JavaServer Pages)の例")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),s._v("@ page contentType"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text/html"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("html"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("head"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("title"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("IIJ "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Bootcamp")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("title"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("head"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("body"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token generics"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("p"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("System")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("out"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("println")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("p"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n現在時刻"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("new")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[t("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("java"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("util"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")])]),s._v("Date")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("%")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("body"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("/")]),s._v("html"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br")])]),t("ol",[t("li",[s._v("1995年Sun Microsystems社がJava言語を売り出した。\n"),t("ul",[t("li",[s._v("最初にアピールした"),t("code",[s._v("Applet")]),s._v("は、Webページの中にJavaのサンドボックス環境を埋め込んでアプリケーションを実行するというものだった。しかし制約が大きいうえにマシンパワーを要求するので、実用的なアプリケーションを作る環境としては、流行らなかった。")])])]),s._v(" "),t("li",[s._v("しかしサーバサイドの技術として発表されたサーブレットは2000年ごろから流行し始め、2001年にStrutsが登場するとその人気は決定的になった。\n"),t("ol",[t("li",[s._v("サーブレットはHTTPリクエストを(CGIのようにプロセスをforkするのではなく)スレッドで処理するので性能が高かった。")]),s._v(" "),t("li",[s._v("Javaは静的に型付けされた言語であるため、Javaで書かれたアプリケーションはPHPよりも品質を確保しやすいかった。")]),s._v(" "),t("li",[s._v("WebアプリケーションフレームワークであるStrutsを使うと、プログラムを一定のスタイルで記述することを助け、同時に大人数で分業することを助けた。規模の大きなエンタープライズシステムの実装が可能になった。")]),s._v(" "),t("li",[s._v("Javaで書かれたコードはポータビリティがあり、サーバのOSやCPUが変わっても、そのまま実行できた。(まだx86系のCPUが市場を独占しておらず、SPARCやAlphaなどのCPUもある程度のシェアを持っていた。)")])])]),s._v(" "),t("li",[s._v("かくしてカジュアルな(コンシューマ向けの)WebアプリケーションはPHPで、シリアスな(エンタープライズ向けの)WebアプリケーションはJavaサーブレットで書く、という時代が続くことになった。")])]),s._v(" "),t("h3",{attrs:{id:"java-ee-spring"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#java-ee-spring"}},[s._v("#")]),s._v(" Java EE / Spring")]),s._v(" "),t("p",[s._v("(Java EE 1999年 / Spring 2002年)")]),s._v(" "),t("p",[s._v("※ サンプルは適当です")]),s._v(" "),t("p",[s._v("JavaEE")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@ManagedBean")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("name"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"HelloBootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RequestScoped")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloBootcamp")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("private")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" message"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("/** Creates a new instance of HelloBootcamp */")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloBootcamp")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("this")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("message "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")]),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@EJB")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("private")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("MessageFacade")]),s._v(" messageFacade"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("*")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("getMessage")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("this")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("message"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br")])]),t("p",[s._v("Spring Framework")]),s._v(" "),t("div",{staticClass:"language-java line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-java"}},[t("code",[t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RestController")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloController")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[s._v("@RequestMapping")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"/"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("public")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("String")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("index")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Welcom to IIJ Bootcamp"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("ol",[t("li",[s._v("Sun Microsystemsはサーブレットの成功に気を良くして、これを一層強力に推進してエンタープライズの世界を支配しようと試みた。そうして出てきたのはJava EE(Enterprise Edition)であった。")]),s._v(" "),t("li",[s._v("Java EEは、エンタープライズアプリケーションを多数のサーバの連携する分散処理を通じて実現することを構想し、その中核技術としてEJB(Enterprise JavaBeans)を据えた。EJBを使うと、ネットワーク越しにJavaのオブジェクトが通信し合い、データベースへの永続化も含めてエレガントに処理できるはずだった。Sun Microsystemsの制定したJava EE仕様を実装するアプリケーションサーバ製品が複数のベンダーから出荷され、活況を呈した。")]),s._v(" "),t("li",[s._v("だが、実際のJava EEアプリケーションサーバ製品は不安定で性能も悪く、プログラミングも難しいものであった。人々はJava EEを信じて使い続けていたが、疑問も大きく膨らんでいった。")]),s._v(" "),t("li",[s._v("そこに登場したのがSpring Frameworkだった(2002年頃)。\n"),t("ul",[t("li",[s._v("作者のRod JohnsonがExpertt One-on-One J2EE Design and Developmentとともに世に問うたもの。")]),s._v(" "),t("li",[s._v("Java EE(J2EE) の欠点を指摘し、EJB、とりわけ"),t("code",[s._v("Entity Beans")]),s._v("を使うことは断念し、POJO(Plain Old Java Object) をベースに開発することを提唱した。")]),s._v(" "),t("li",[s._v("DI (Dependency Injecttion) のアイデアを普及させ、大規模なJavaアプリケーションを効率よく分業体制で実装する道を切り開いた。")])])]),s._v(" "),t("li",[s._v("Spring Frameworkは一世を風靡しただけでなく、今日まで人気を失うことなく、利用されている。\n"),t("ul",[t("li",[s._v("StrutsはStrus1の後継バージョンであるStruts2が、Struts1とまったく互換性がなかったため、Struts1を採用していた開発会社に受け入れられなかった。")]),s._v(" "),t("li",[s._v("その後脆弱性問題を連発したため、今日ではまったく人気がない。")])])])]),s._v(" "),t("h3",{attrs:{id:"ruby-on-rails"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ruby-on-rails"}},[s._v("#")]),s._v(" Ruby on Rails")]),s._v(" "),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("HelloController")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" ApplicationController\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token method-definition"}},[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("hello")])]),s._v("\n render "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":html")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=>")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'

Welcom to IIJ Bootcamp

'")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token method-definition"}},[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("hello_json")])]),s._v("\n render "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":json")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=>")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("msg")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Welcom to IIJ Bootcamp'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br")])]),t("ol",[t("li",[s._v("2004年、37signals社がbasecampというプロジェクト管理アプリケーションの実装に使用していたRuby on RailsというWebアプリケーションフレームワークを発表した。Railsは非常にインパクトのあるフレームワークで、以降のサーバサイドプログラミングの世界を一変させてしまった。")]),s._v(" "),t("li",[s._v("その特徴を列挙すると以下のとおり。\n"),t("ol",[t("li",[s._v("2つの哲学。「同じことを繰り返さない DRY: Don't repeat yourself」「設定より規約 Convention over Configuration」\n"),t("ul",[t("li",[s._v("Strutsでは互いに関連し合う複雑な設定ファイルが多く必要だった\n"),t("ul",[t("li",[s._v("ルーティング(あるURLをどのアクションクラスで処理するかのマッピング)やアクションが処理するリクエストのフォームを記述するクラス、テンプレートの中で使用するタグライブラリの定義など")]),s._v(" "),t("li",[s._v("ほとんどの設定項目は、自動的なものであり、設定ファイルのメンテナンスは大量の単純作業であった。")])])]),s._v(" "),t("li",[s._v("そこで多くの現場ではExcelなどで主要設定項目を管理し、そのExcelファイルからマクロで個々の設定ファイルを生成するようなことが行われていた。")]),s._v(" "),t("li",[s._v("Railsでは、これを「デフォルトで定められているディレクトリ構造や命名規則に沿っている限り、設定ファイルは不要とする(特別な場合だけ、設定ファイルを書く)」という方法で解決した。")]),s._v(" "),t("li",[s._v("たとえばRDBMSのpersonsテーブルに対応するモデルクラスを、ModelsディレクトリにあるPerson.rbファイルとして記述すれば、自動的にDBアクセス可能とするというような具合である。")]),s._v(" "),t("li",[s._v("こうした開発者体験(Developer Experience)の良さは、Rubyが非常にメタプログラミングをしやすい言語であることで成り立っている。\n"),t("ul",[t("li",[s._v("Rails 独自の拡張や構文を多数実装することで、上記の哲学を実現している。")])])])])]),s._v(" "),t("li",[s._v("コマンドラインユーティリティによる開発のサポート\n"),t("ul",[t("li",[s._v("たとえばあるURLに対応するコントローラクラスのスケルトンをコマンドラインユーティリティから生成できる。")]),s._v(" "),t("li",[s._v("このようなユーティリティを提供することで、開発者を単純作業から解放し、価値あるコードを書くことへ集中できるようにした。")])])]),s._v(" "),t("li",[s._v("Ruby on Railsに触発されて、別の言語でも同様のフレームワークが多数開発された。\n"),t("ul",[t("li",[s._v("PHP: CakePHP")]),s._v(" "),t("li",[s._v("Java: JBoss Seam, Java EE 6, Grails(Groovyを使う)")]),s._v(" "),t("li",[s._v("Python: Django")])])])])]),s._v(" "),t("li",[s._v("今でも第一線で使われており、githubもRailsで作られ続けている。一方で一時期より採用されることは減ってきた。")])]),s._v(" "),t("ul",[t("li",[s._v("「マイクロサービス」が注目され、小さなアプリケーションを多く作るようになった\n"),t("ul",[t("li",[s._v("Railsはどちらかというと大きなアプリを作るためのフレームワークであり、マイクロサービスと対比してモノリスアプリの例として扱われる")]),s._v(" "),t("li",[s._v("とはいえ最近はまた一巡してモジュラーモノリスなど大きなアプリが着目されており、流れが変わりつつあるかもしれない")])])]),s._v(" "),t("li",[s._v("pythonが言語として人気であり、その流れでDjangoが採用されることが増えた(?)")]),s._v(" "),t("li",[s._v("Goなどに比べてパフォーマンス面で不利")])]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("rails generate controller User name:string email:string\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("Person")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" ActiveRecord"),t("span",{pre:!0,attrs:{class:"token double-colon punctuation"}},[s._v("::")]),s._v("Base\n attr_accessible "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":email")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v(":name")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("end")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("div",{staticClass:"language-ruby line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-ruby"}},[t("code",[s._v("person "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Person"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("find"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# id=1なデータをDBで検索する")]),s._v("\n\nPerson"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("create"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("email")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'hoge@example.com'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token symbol"}},[s._v("username")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string-literal"}},[t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'hoge'")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# データの作成(DBにinsert)")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("h3",{attrs:{id:"ajaxの出現-フロントエンド-apiサーバの時代"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#ajaxの出現-フロントエンド-apiサーバの時代"}},[s._v("#")]),s._v(" Ajaxの出現 / フロントエンド+APIサーバの時代")]),s._v(" "),t("ol",[t("li",[s._v("Google MapsおよびGmailの出現により、「画面遷移を伴わないWebアプリケーション」というものがユーザーに認知され始めた。2005年ごろのことである。")]),s._v(" "),t("li",[s._v("Googleのエンジニアたちの使った技法は、技術としてはそれ以前から存在していたが誰も注目してこなかったXMLHttpRequestというJavaScriptの機能を初めて本格的に使用するものだった。\n"),t("ol",[t("li",[s._v("この技法をAsynchronous JavaScript + XMLの頭文字をとってAjax (エイジャックス) と呼ぶようになった。")])])]),s._v(" "),t("li",[s._v("StrutsやRuby on Railsはサーバサイド(バックエンド)側でリクエストを処理して画面も生成するというようなスタイルが中心だった。しかしAjaxが人気を集めるようになるとクライアント(フロントエンド)側で画面描画をすべて行い、バックエンドにはAPIサーバのみを置くというスタイルが人気を集めるようになった。\n"),t("ol",[t("li",[s._v("画面遷移を伴わないWebアプリケーションのことをSPA (Single Page Application) などと呼ぶ。")]),s._v(" "),t("li",[s._v("このスタイルが定着すると、デスクトップアプリケーションと比較しても遜色ないUIのWebアプリケーションが当たり前のように期待されるようになっていった。")]),s._v(" "),t("li",[s._v("要求の高度化に応えるため、フロントエンド側のフレームワークが非常に速いペースで開発されているのが今日の状況である。今日、人気のあるフロントエンド・フレームワークとしてReact (Facebook)、Angular (Google)、Vue.js (Evan You)などがある。")])])])]),s._v(" "),t("h3",{attrs:{id:"node-js"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#node-js"}},[s._v("#")]),s._v(" Node.js")]),s._v(" "),t("p",[s._v("Perlから始まり、ここまで出てきたJavaやRailsは基本的に同期的なI/Oとシングルプロセスで動作する。\nそのため複数のリクエストを同時に処理するためにはマルチプロセスやスレッドといった仕組みを利用する必要があった。")]),s._v(" "),t("ul",[t("li",[s._v("マルチプロセス: リクエストごと、あるいは事前にプロセスを複数立ち上げておき、1つのリクエストを1プロセスに割り当てる\n"),t("ul",[t("li",[s._v("CGI, FastCGI, Railsのpassengerなど。Apache自体も長らくこの仕組みだった")])])]),s._v(" "),t("li",[s._v("スレッド: 言語内で並列処理用の軽量なプロセスを立ち上げる。負荷は低いが言語ごとに癖がある\n"),t("ul",[t("li",[s._v("Javaなど")])])]),s._v(" "),t("li",[s._v("上の二つは組み合わせて利用する場合もある")])]),s._v(" "),t("p",[t("img",{attrs:{src:a(467),alt:"apache_railes",title:"apache_railes"}})]),s._v(" "),t("p",[s._v("しかしインターネット利用者に増加にともなってWebサービスへのアクセス量も増え、プロセスのforkやスレッドによる処理モデルの限界が表面化してきた。特にプロセスの場合は1サーバあたりで起動できるプロセス数には限界がある他、プロセスを作るコスト(メモリ消費など)が無視できなくなってきたのである。\n(C10K問題と呼ばれる)")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),t("p",[s._v("たとえば32bit環境のlinuxサーバでは、プロセスの作成上限は管理番号(PID)の上限となる32768になる。\nまた1スレッドあたり数MBのメモリを使うとすると、8GBのメモリを積んだサーバでは4000ほどが上限になる。\n(あくまで単純に計算した場合の理論値)")])]),s._v(" "),t("p",[s._v("この問題への解決として、Node.jsをはじめとした非同期I/OとEventDrivenなアーキテクチャが注目された。\nNode.jsはJavaScriptの実行環境の一つで、I/O待ち(HDDへの書き込みなど)中に他の処理を行うことで、1プロセスで複数のリクエストを同時に処理することができる。")]),s._v(" "),t("p",[s._v("Node.jsのイベントループによる非同期I/Oの実現")]),s._v(" "),t("p",[t("img",{attrs:{src:a(468),alt:"event-loop",title:"event-loop"}})]),s._v(" "),t("p",[s._v("Node.jsの中でリクエストを並列に捌けるためWebアプリ用にプロセスをforkする必要がなくなり、裏で動いているNode.jsのサーバにリクエストをただプロキシするだけで良くなった。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(469),alt:"node",title:"node"}})]),s._v(" "),t("p",[s._v("開発スタイルの特徴としては以下が挙げられる。")]),s._v(" "),t("ul",[t("li",[s._v("フロントエンド開発と同じJavaScriptで書けるので、1サービスを作るのに複数の言語を扱わなくてよくなる")]),s._v(" "),t("li",[s._v("豊富なライブラリやツールの選択肢がある")]),s._v(" "),t("li",[s._v("反面EventDrivenな実装はコードが複雑になりがちで、どちらかというと小規模な実装向け\n"),t("ul",[t("li",[s._v("TypeScriptによる型の導入やasync/await記法の導入などで改善されつつはある")])])]),s._v(" "),t("li",[s._v("できるだけ自分で実装せずにライブラリを使うことがよしとされる風潮があり、ライブラリの依存関係が膨らみがち\n"),t("ul",[t("li",[s._v("正しくはあるが、小さな機能のために追加ライブラリをパッケージする必要があり、依存関係の複雑さやビルド時間の増加を招く")]),s._v(" "),t("li",[s._v("Rubyの頃からある業界的な課題ではあるが、Node.jsでは特に顕著")])])])]),s._v(" "),t("p",[s._v("最近ではSPAフレームワークからの流れでSSR(Server Side Rendering)を採用するサービスも増えており、その実行環境としてNode.jsが引き続き使われている。")]),s._v(" "),t("p",[s._v("最近は "),t("a",{attrs:{href:"https://deno.land/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Deno"),t("OutboundLink")],1),s._v(" というTypeScriptがネイティブで動作するランタイムも流行り始めている。")]),s._v(" "),t("h3",{attrs:{id:"go言語"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#go言語"}},[s._v("#")]),s._v(" Go言語")]),s._v(" "),t("p",[s._v("2016年くらいから利用例の増えてきたプログラミング言語で、静的型付け・シンプルな言語体系・高速な動作・並行処理が得意などの特徴がある。\nRubyやPythonなどのスクリプト言語のような開発スピードと、JavaやCのような静的型付けによる安全性・実行の速さを両立していることで、Webサービスのバックエンドとして使われることが増えた。\nRubyやPython、Javaなどのように実行環境をインストールする必要がなく、コンパイルしたバイナリファイル1つで動作するため、デプロイや環境構築が容易なのも特徴。\nまたGoにはgoroutineという軽量なスレッドのような並行処理の仕組みがあり、このgoroutineを使って複数のリクエストを処理することができる。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(470),alt:"go",title:"go"}})]),s._v(" "),t("p",[s._v("開発スタイルとしては以下のような特徴がある。")]),s._v(" "),t("ul",[t("li",[s._v("あまりライブラリやフレームワークを使わずに、自分で実装することが推奨される\n"),t("ul",[t("li",[s._v("標準ライブラリが優秀で、大抵の機能はフレームワークがなくても十分実装できる")]),s._v(" "),t("li",[s._v("抽象化関連の機能も少ないためフレームワークの旨味があまりなく、デファクトが生まれづらい")])])]),s._v(" "),t("li",[s._v("goroutineという仕組みでシンプルに並行処理が書ける")]),s._v(" "),t("li",[s._v("言語仕様がシンプルなのと静的型付けなこともあり、linterやコード補完ツールが作りやすい\n"),t("ul",[t("li",[s._v("言語解析をしてくれる"),t("code",[s._v("analysis package")]),s._v("が公式から提供されている")])])]),s._v(" "),t("li",[s._v("コーディング規約がある程度公式で決まっており、誰が書いても同じ書き方になる\n"),t("ul",[t("li",[s._v("複数人での開発がやりやすい")])])]),s._v(" "),t("li",[s._v("コンパイル言語なので(スクリプト言語に比べると)デバッグが難しい")]),s._v(" "),t("li",[s._v("Railsのようなフレームワークに頼らず、自力でアプリケーションを構築していく必要がある")])]),s._v(" "),t("h3",{attrs:{id:"その先"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#その先"}},[s._v("#")]),s._v(" その先...")]),s._v(" "),t("ul",[t("li",[s._v("Haskellなどの関数型言語が流行りそう?")]),s._v(" "),t("li",[s._v("Rustはいい言語だが書くのが難しく、どちらかというとOSなどのシステムプログラミング向け\n"),t("ul",[t("li",[s._v("Rustのメモリ管理はGC(ガベージコレクト)を起こさないためのもの")]),s._v(" "),t("li",[s._v("Webアプリの実行環境はある程度メモリやCPUを富豪的に使えるため、書きやすさを優先してGoやRuby, JavaなどGCのある言語が使われる傾向にある")])])])]),s._v(" "),t("h2",{attrs:{id:"アプリケーションプログラミングインタフェース-api-の色々"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#アプリケーションプログラミングインタフェース-api-の色々"}},[s._v("#")]),s._v(" アプリケーションプログラミングインタフェース(API) の色々")]),s._v(" "),t("p",[s._v("API(Application Programming Interface)とはアプリケーションが他のソフトウェアの機能を利用するための仕組みを指す。\nWebアプリケーションの文脈では主にhttpプロトコル越しに他のWebアプリケーションにrequestを送信し、responseを受け取る仕組みを指す。")]),s._v(" "),t("p",[s._v("一番分かりやすいのはブラウザ上で動作するJavaScriptがサーバのAPIを叩いてJSON形式のresponseを受け取るもの。\n他に実は裏側でサーバ同士がAPIでやり取りしていることもよくあるし、サーバからさらに外部のサービスを呼び出す場合もある。")]),s._v(" "),t("p",[s._v("APIをどのような形式で実装するかは非常に重要な問題で、過去から現在に至るまで様々な設計・実装手法が存在しています。\nプログラミング言語と同様に長い変遷の歴史があるので、そちらを紹介していこうと思います。")]),s._v(" "),t("h3",{attrs:{id:"rpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rpc"}},[s._v("#")]),s._v(" RPC")]),s._v(" "),t("p",[s._v("そもそもプログラムからネットワーク越しに外部のプログラムの機能を実行する仕組みをRPC(Remote Procedure Call)と呼びます。\n黎明期におけるRPCはHTTPなどのWebの仕組みは前提にしておらず、各言語や実装ごとに独自の仕組みで動作するものでした。")]),s._v(" "),t("p",[s._v("その根底には「遠隔地(remote)で動いているプログラムの関数を実行する」という思想があり、RPC系のAPIは関数名と引数を指定してレスポンスを受け取るというイメージで使われます。")]),s._v(" "),t("h3",{attrs:{id:"xml-rpc-json-rpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#xml-rpc-json-rpc"}},[s._v("#")]),s._v(" XML/RPC(JSON-RPC)")]),s._v(" "),t("p",[s._v("独自の仕組みで動いていたRPCをHTTP通信を前提にして規格として整えたものはXML/RPCと呼ばれる。\n字の如くXML形式のデータをやり取りし、そのフォーマットなどを定めたものなっている。")]),s._v(" "),t("p",[s._v("リクエストの例")]),s._v(" "),t("div",{staticClass:"language-xml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-xml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token prolog"}},[s._v('')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodCall")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodName")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("examples.getStateName"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("params")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("param")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("i4")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("40"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("p",[s._v("レスポンスの例")]),s._v(" "),t("div",{staticClass:"language-xml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-xml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token prolog"}},[s._v('')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("methodResponse")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("params")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("param")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("string")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("South Dakota"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br")])]),t("p",[s._v("XMLの代わりにJSON形式でやり取りされる場合はJSON-RPCと呼ばれる。")]),s._v(" "),t("h3",{attrs:{id:"soap"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#soap"}},[s._v("#")]),s._v(" SOAP")]),s._v(" "),t("p",[s._v("XML/RPCを発展させたもの?\n主にエンタープライズの文脈で企業同士がデータのやり取りをするために利用されていたらしい。")]),s._v(" "),t("p",[s._v("(よく知らないので誰か追記してください)")]),s._v(" "),t("h3",{attrs:{id:"rest"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#rest"}},[s._v("#")]),s._v(" REST")]),s._v(" "),t("p",[s._v("RPCは相手がどのようなメソッド(関数)を実装しているのか、そのメソッドがどのような挙動をするのか定まっておらず、統一感がなかった。\nそこで「APIの設計思想」のようなものとしてRESTが登場し、そのRESTの思想を満たすようなAPIをRESTful APIと呼ぶ。")]),s._v(" "),t("p",[s._v("その原則には以下のような項目が挙げられる。")]),s._v(" "),t("ul",[t("li",[s._v("リソースをURLを通して表現すること\n"),t("ul",[t("li",[s._v("例えば "),t("code",[s._v("example.com/book/001")]),s._v(" は「"),t("code",[s._v("001")]),s._v("というIDが付けられた"),t("code",[s._v("book")]),s._v("」というリソースを表す")])])]),s._v(" "),t("li",[s._v("セッションなどの状態管理を行わないこと(=ステートレス性)")]),s._v(" "),t("li",[s._v("HTTPにおける GET/POST/PUT/DELETE の各メソッドをそのままリソースの 取得/作成/編集/削除 に対応させる\n"),t("ul",[t("li",[t("code",[s._v("GET example.com/book/")]),s._v(" をするとbookの一覧が取得できる")]),s._v(" "),t("li",[t("code",[s._v("POST example.com/book/")]),s._v(" で新しいbookを追加する")]),s._v(" "),t("li",[t("code",[s._v("GET example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookの詳細を取得する")]),s._v(" "),t("li",[t("code",[s._v("PUT example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookを更新する")]),s._v(" "),t("li",[t("code",[s._v("DELETE example.com/book/001")]),s._v(" で"),t("code",[s._v("ID:001")]),s._v("のbookを削除する")])])])]),s._v(" "),t("p",[s._v("とはいえ厳密にRESTに従っているものは少なく、多少違反していてもざっくり「REST API」と呼ばれることが多い。\n(なんちゃってRESTとか言ったりする)")]),s._v(" "),t("p",[s._v("元々は「到達可能性」のような概念が謳われており、例えば"),t("code",[s._v("GET")]),s._v("で取得した内容に他のリソースのURLが含まれることで、人間がブラウザを使うのと同じように機械が情報を自律的に探索可能にすることも目指されていた。\nその未来は来ず、世の中にはなんちゃってRESTが便利に使われている。")]),s._v(" "),t("p",[s._v("データフォーマットには基本的にJSONが使われる。")]),s._v(" "),t("h3",{attrs:{id:"openapi"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#openapi"}},[s._v("#")]),s._v(" OpenAPI")]),s._v(" "),t("p",[s._v("REST APIの仕様を機械可読可能な形で記述するための仕様。\n元々「Swagger」という名前だったのが、汎用的な仕様として定義するにあたって「OpenAPI」と名前が付けられた。")]),s._v(" "),t("p",[s._v("以下はymlで書かれたAPI仕様の例")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("openapi")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" 3.0.3\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("info")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("title")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp example\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("|")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("\n This is a sample Pet Store Server.\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("version")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"1.0"')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("paths")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("/pet")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("post")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("tags")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" pet\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("summary")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Add a new pet to the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Add a new pet to the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("requestBody")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Create a new pet in the store\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("responses")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'200'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Successful operation\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v(" \n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'405'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Invalid input\n /pet/"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("petId"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("get")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("summary")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Find pet by ID\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Returns a single pet\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("parameters")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" petId\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("in")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" path\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ID of pet to return\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" integer\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("format")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" int64\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("responses")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'200'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" successful operation\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("content")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("application/json")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schema")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("$ref")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'#/components/schemas/Pet'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'400'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Invalid ID supplied\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("'404'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("description")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Pet not found\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("components")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("schemas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("Pet")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("required")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" name\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" photoUrls\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" object\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("properties")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("id")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" integer\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("format")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" int64\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("example")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" string\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("example")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" doggie\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br"),t("span",{staticClass:"line-number"},[s._v("46")]),t("br"),t("span",{staticClass:"line-number"},[s._v("47")]),t("br"),t("span",{staticClass:"line-number"},[s._v("48")]),t("br"),t("span",{staticClass:"line-number"},[s._v("49")]),t("br"),t("span",{staticClass:"line-number"},[s._v("50")]),t("br"),t("span",{staticClass:"line-number"},[s._v("51")]),t("br"),t("span",{staticClass:"line-number"},[s._v("52")]),t("br"),t("span",{staticClass:"line-number"},[s._v("53")]),t("br"),t("span",{staticClass:"line-number"},[s._v("54")]),t("br"),t("span",{staticClass:"line-number"},[s._v("55")]),t("br"),t("span",{staticClass:"line-number"},[s._v("56")]),t("br"),t("span",{staticClass:"line-number"},[s._v("57")]),t("br"),t("span",{staticClass:"line-number"},[s._v("58")]),t("br"),t("span",{staticClass:"line-number"},[s._v("59")]),t("br"),t("span",{staticClass:"line-number"},[s._v("60")]),t("br"),t("span",{staticClass:"line-number"},[s._v("61")]),t("br"),t("span",{staticClass:"line-number"},[s._v("62")]),t("br"),t("span",{staticClass:"line-number"},[s._v("63")]),t("br"),t("span",{staticClass:"line-number"},[s._v("64")]),t("br"),t("span",{staticClass:"line-number"},[s._v("65")]),t("br"),t("span",{staticClass:"line-number"},[s._v("66")]),t("br"),t("span",{staticClass:"line-number"},[s._v("67")]),t("br")])]),t("p",[s._v("仕様に従って書かれているので、これを画面で作成するのも簡単ですし、綺麗に整形することもできます。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(471),alt:"",title:"open_api_1"}})]),s._v(" "),t("p",[t("img",{attrs:{src:a(472),alt:"",title:"open_api_2"}})]),s._v(" "),t("p",[t("a",{attrs:{href:"https://editor.swagger.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://editor.swagger.io/"),t("OutboundLink")],1),s._v(" で触れるのでぜひ試してみてください。")]),s._v(" "),t("p",[s._v("APIを作る場合必ず仕様書を用意しますが、open_apiのフォーマットに従うと何を書くべきなのか明確ですし、そこから綺麗な形式に出力することができます。\nまたopen_apiの仕様からコードを自動生成するツールも多数存在しており、REST APIを設計する場合、可能な限りopen_apiで仕様を定義しておくと後々役に立ちます。")]),s._v(" "),t("h3",{attrs:{id:"graphql"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#graphql"}},[s._v("#")]),s._v(" GraphQL")]),s._v(" "),t("p",[s._v("RESTに代表されるように、データへのアクセス方法や形式(レスポンスのJSON構造など)はサーバ側が決め、クライアントはその定義に従ってAPIを叩くのが基本でした。\nしかしモバイルアプリによる利用が増える中で、ブラウザからのアクセスとモバイルアプリからのアクセスで異なるデータ形式が望ましいケースが出てきました。\nこういったユースケースに対応するため、APIで取得するデータ形式をクライアント側で指定できるのがGraphQLです。")]),s._v(" "),t("p",[s._v("単純な例では、例えばREST APIで"),t("code",[s._v("GET https://example.com/persons")]),s._v("すると以下のようなデータが返ってきたとします。")]),s._v(" "),t("div",{staticClass:"language-json line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-json"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group_id"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"profile"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque nisl eros, pulvinar facilisis."')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group_id"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"profile"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero."')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n ...\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br")])]),t("p",[s._v("ここでモバイルアプリは"),t("code",[s._v("profile")]),s._v("が不要な一方、"),t("code",[s._v("group")]),s._v("の情報も一緒にUIに出したいとします。\nその場合"),t("code",[s._v("profile")]),s._v("の長いデータは完全に無駄な通信ですし、"),t("code",[s._v("group")]),s._v("の情報を問い合わせるために"),t("code",[s._v("GET https://example.com/groups/5")]),s._v("をしないといけません。モバイルアプリにとって理想的なAPIにするためには、サーバ側に新しいAPIを作ってもらう必要があります。")]),s._v(" "),t("p",[s._v("これをクライアント側で制御するのがGraphQLのやりたいことで、例えばGraphQLでは以下のようなクエリをサーバの"),t("code",[s._v("https://example.com/graphql")]),s._v("にPOSTします。")]),s._v(" "),t("div",{staticClass:"language-graphql line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-graphql"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("query")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token object"}},[s._v("persons")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("name")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("email")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token object"}},[s._v("group")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v("name")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("p",[s._v("するとサーバが以下のようなレスポンスを返してくるという算段です。")]),s._v(" "),t("div",{staticClass:"language-json line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-json"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"data"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"persons"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"tanaka@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Engineering Team"')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"higashi@example.com"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"group"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token property"}},[s._v('"name"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Marketing Team"')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n ...\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br")])]),t("p",[s._v("様々なユースケースを持つクライアントが多く存在するような場合非常に強力です。"),t("a",{attrs:{href:"https://docs.github.com/ja/graphql",target:"_blank",rel:"noopener noreferrer"}},[s._v("githubのAPI"),t("OutboundLink")],1),s._v(" は多数向けに公開されデータ構造も複雑なため、まさにgraphqlがハマるパターンです。")]),s._v(" "),t("p",[s._v("一方でgraphqlとしては一発でデータを取れているように見えても、データベース上は相変わらずperson -> groupとSQLを2回以上叩く必要があるかもしれません。\nクライアント側のユースケースが限られサーバ側の実装変更が可能であれば、ユースケースに合わせて効率よくデータを取得できるAPIを作った方がパフォーマンストラブルを引き起こさずに済むでしょう。")]),s._v(" "),t("h3",{attrs:{id:"grpc"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#grpc"}},[s._v("#")]),s._v(" gRPC")]),s._v(" "),t("p",[s._v("gRPCは名前の通りRPC(Remote Procedure Call)を実現するためのプロトコルです。\nAPIを "),t("a",{attrs:{href:"https://protobuf.dev/overview/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Protocol Buffers"),t("OutboundLink")],1),s._v(" という形式で定義し、そのprotoファイルを元に各言語用のコードを生成することで、同じAPI定義を異なる言語で共有することが容易にできます。\ntransport層としてhttp2を前提にしており、単純なrequest-responseだけではなく双方向のstreamingもサポートしています。\nまた実際にやり取りされるデータは最小限のバイナリになっており、jsonに比べて低容量に通信ができます。")]),s._v(" "),t("p",[s._v("以下はprotoファイルの例です")]),s._v(" "),t("div",{staticClass:"language-proto line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("// GetPersonRequest を受け取って GetPersonResponse を返すメソッドの定義\nservice Person {\n rpc GetPerson (GetPersonRequest) returns (GetPersonResponse) {}\n}\n\n// GetPersonsRequest のリクエスト定義\nmessage GetPersonsRequest {\n string name = 1;\n}\n\n// HelloReply のレスポンス定義\nmessage GetPersonResponse {\n Person person = 1;\n\n message Person {\n string name = 1;\n string email = 2;\n string profile = 3;\n }\n}\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br")])]),t("p",[s._v("このproto定義から各言語向けに型定義を含めたコードを生成するため、実装が自由なOpenAPIに比べるとより厳密にAPIを実装できます。")]),s._v(" "),t("credit-footer")],1)}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/11.5fa02e65.js b/assets/js/11.5fa02e65.js new file mode 100644 index 00000000..6459acd9 --- /dev/null +++ b/assets/js/11.5fa02e65.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{353:function(t,s,a){t.exports=a.p+"assets/img/docker01.9c3fed93.jpg"},354:function(t,s){t.exports="data:image/jpeg;base64,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"},355:function(t,s){t.exports="data:image/jpeg;base64,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"},356:function(t,s){t.exports="data:image/jpeg;base64,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"},357:function(t,s){t.exports="data:image/jpeg;base64,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"},358:function(t,s,a){t.exports=a.p+"assets/img/docker06.f94651f1.jpg"},359:function(t,s,a){t.exports=a.p+"assets/img/DB00.3fdfd46b.jpg"},360:function(t,s,a){t.exports=a.p+"assets/img/DB01.e9d2dca0.jpg"},361:function(t,s,a){t.exports=a.p+"assets/img/DB02.deae098c.jpg"},362:function(t,s,a){t.exports=a.p+"assets/img/DB03.67543a21.jpg"},363:function(t,s,a){t.exports=a.p+"assets/img/DB04.195ebfdf.jpg"},515:function(t,s,a){"use strict";a.r(s);var e=a(10),r=Object(e.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"リレーショナルdbを触ってみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#リレーショナルdbを触ってみる"}},[t._v("#")]),t._v(" リレーショナルDBを触ってみる")]),t._v(" "),s("hr"),t._v(" "),s("h2",{attrs:{id:"事前準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#事前準備"}},[t._v("#")]),t._v(" <事前準備>")]),t._v(" "),s("ul",[s("li",[t._v("Dockerがインストールされていること")]),t._v(" "),s("li",[t._v("PowerShellが利用できる状態であること")]),t._v(" "),s("li",[t._v("インターネットに接続できていること")])]),t._v(" "),s("h1",{attrs:{id:"postgresqlについて"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#postgresqlについて"}},[t._v("#")]),t._v(" PostgreSQLについて")]),t._v(" "),s("h3",{attrs:{id:"呼び方"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#呼び方"}},[t._v("#")]),t._v(" 呼び方")]),t._v(" "),s("p",[t._v("「ポストグレス キューエル」らしいのですが、この呼び方している人は少ないように感じます。"),s("br"),t._v("\nよく聞くのは「ポスグレ」、「ポストグレス」です。")]),t._v(" "),s("h3",{attrs:{id:"日本postgresqlユーザ会"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#日本postgresqlユーザ会"}},[t._v("#")]),t._v(" 日本PostgreSQLユーザ会")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://www.postgresql.jp/",target:"_blank",rel:"noopener noreferrer"}},[t._v("日本PostgreSQLユーザ会"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("日本国内でPostgreSQLデータベースを使用するユーザーのコミュニティおよび組織です。")]),t._v(" "),s("li",[t._v("このユーザ会は、PostgreSQLに関心を持つ人々が情報共有や交流を行い、技術的な知識を向上させることを目的としています。")])]),t._v(" "),s("h3",{attrs:{id:"バージョン体系-超抜粋"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#バージョン体系-超抜粋"}},[t._v("#")]),t._v(" バージョン体系(超抜粋)")]),t._v(" "),s("p",[t._v("※8.0よりも前のバージョン(6.0や7.0)については省略します。")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",{staticStyle:{"text-align":"right"}},[t._v("メジャーバージョン")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("リリース日")]),t._v(" "),s("th",{staticStyle:{"text-align":"right"}},[t._v("最新マイナー版")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("最新版リリース日")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("サポート期限")])])]),t._v(" "),s("tbody",[s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("8.0")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2005/11/8")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("8.0.26")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/4")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/1")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("8.1.x~8.4.x")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("9.0")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/9/20")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("9.0.23")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2015/10/8")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/8")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("9.1.x~9.6.x")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("10")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2017/10/5")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("10.23")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/11/10")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/11/10")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2018/10/18")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("11.22")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/11/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/11/9")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("12")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2019/10/3")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("12.19")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/5/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/11/14")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("13")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2020/9/24")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("13.15")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/5/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2025/11/13")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("14")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2021/9/30")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("14.12")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/5/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2026/11/12")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("15")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/10/13")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("15.7")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/5/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2027/11/11")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("16")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/9/14")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("16.3")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/5/9")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2028/11/9")])])])]),t._v(" "),s("p",[t._v("※バージョン体系がPostgreSQL10より変更されました。")]),t._v(" "),s("p",[t._v("Postgresql 10以前 ⇒  "),s("span",{staticStyle:{"font-size":"200%",color:"red"}},[s("strong",[t._v("9.0")])]),t._v(" ."),s("span",{staticStyle:{"font-size":"200%",color:"blue"}},[t._v("23")]),s("br"),t._v(" "),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("9.0の部分がメジャーバージョン")]),t._v("で"),s("span",{staticStyle:{"font-size":"100%",color:"blue"}},[t._v("23がマイナーバージョン")]),t._v("となります。"),s("br"),t._v(" "),s("br"),t._v("\nPostgresql 10以降 ⇒  "),s("span",{staticStyle:{"font-size":"200%",color:"red"}},[s("strong",[t._v("10")])]),t._v(" ."),s("span",{staticStyle:{"font-size":"200%",color:"blue"}},[t._v("22")]),s("br"),t._v(" "),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("10の部分がメジャーバージョン")]),t._v("で"),s("span",{staticStyle:{"font-size":"100%",color:"blue"}},[t._v("22がマイナーバージョン")]),t._v(" となります。")]),t._v(" "),s("h3",{attrs:{id:"ライセンス"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#ライセンス"}},[t._v("#")]),t._v(" ライセンス")]),t._v(" "),s("p",[t._v("PostgreSQLは、"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("オープンソースのリレーショナルデータベース")]),t._v("管理システムです。"),s("br"),t._v("\nそのライセンスは、PostgreSQL Global Development Group(PGDG)によって開発されたもので以下の2つのライセンスオプションが提供されています。")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("PostgreSQLライセンス(PostgreSQL License\nこれは、PostgreSQLプロジェクトが採用している独自のライセンスです。\nこのライセンスは、商用利用や非商用利用、修正や再配布を含むあらゆる使用形態に対して、\n自由かつ"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("無償で利用することを許可しています。")]),t._v("また、ソースコードの利用や変更、派生物の作成、\nバイナリ形式での再配布なども可能です。そのため、PostgreSQLを自由に使用し、変更や拡張を行い、\nプロジェクトや製品に組み込むことができます。")])]),t._v(" "),s("li",[s("p",[t._v("MIT(マサチューセッツ工科大学)ライセンス\nPostgreSQLプロジェクトは、PostgreSQLライセンスに加えて、一部のコンポーネントについてはMITライセンスも採用しています。\nMITライセンスは、商用利用や非商用利用、修正や再配布を含むあらゆる使用形態に対して、"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("自由かつ無償で利用することを許可")]),t._v("しています。\nただし、著作権表示および本許諾表示をソフトウェアのすべての複製または重要な部分に記載しなければならず、作者または著作権者は、ソフトウェアに関してなんら責任を負わない。")])])]),t._v(" "),s("h1",{attrs:{id:"ハンズオン研修-【データベースに触れてみよう】"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#ハンズオン研修-【データベースに触れてみよう】"}},[t._v("#")]),t._v(" ハンズオン研修 【データベースに触れてみよう】")]),t._v(" "),s("h2",{attrs:{id:"_0-postgresql環境準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-postgresql環境準備"}},[t._v("#")]),t._v(" 0. PostgreSQL環境準備")]),t._v(" "),s("p",[t._v("本演習にて入力するコマンドはおおきく分けて以下の3つにわかれているため、入力する場所には注意する必要があります。")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("1.Linux環境 【 $ 表示のプロンプト】"),s("br"),t._v("\n →  ★0-1、★0-2 、★0-3 での入力先となります。")])]),t._v(" "),s("li",[s("p",[t._v("2.コンテナ環境 【 root@xxx から始まるプロンプト】"),s("br"),t._v("\n →  ★0-4 ★1-1、及び★A-1、★A-2、★B-1先頭行、★B-2 での入力先となります。")])]),t._v(" "),s("li",[s("p",[t._v("3.PostgreSQL環境 【 postgres=# から始まるプロンプト】"),s("br"),t._v("\n →  ★1-2~演習問題まで及び★B-1drop文 の入力先となります。")])])]),t._v(" "),s("p",[t._v("※出力イメージと異なるような結果が表示された際には入力場所をご確認ください。")]),t._v(" "),s("h3",{attrs:{id:"★0-1-postgresql環境のダウンロード"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-1-postgresql環境のダウンロード"}},[t._v("#")]),t._v(" ★0-1 PostgreSQL環境のダウンロード")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、PostgreSQL環境をダウンロードします。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker pull postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ\n"),s("img",{attrs:{src:a(353),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-2-コンテナ起動"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-2-コンテナ起動"}},[t._v("#")]),t._v(" ★0-2 コンテナ起動")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、コンテナ(PostgreSQLも起動します)環境を起動させます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker run --name some-postgres -e POSTGRES_PASSWORD=postgres -d postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(354),alt:""}}),s("br"),t._v("\n※正常に起動すると上記のような64文字の文字列(値は各自で異なります)が表示されます。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-3-コンテナ接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-3-コンテナ接続"}},[t._v("#")]),t._v(" ★0-3 コンテナ接続")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、コンテナに接続します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker exec -it some-postgres /bin/bash\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(355),alt:""}}),s("br"),t._v("\n ※接続に成功すると上記のような最後に「#」が付いた状態で表示されます。"),s("br"),t._v("\n ※「root@」以降の文字列は各自で異なります。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-4-ロケールの確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-4-ロケールの確認"}},[t._v("#")]),t._v(" ★0-4 ロケールの確認")]),t._v(" "),s("p",[t._v("本講義で使用する言語「en_US.utf8」が表示されることを確認します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("locale -a\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(356),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_1-データベースへ接続してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-データベースへ接続してみよう"}},[t._v("#")]),t._v(" 1. データベースへ接続してみよう")]),t._v(" "),s("h3",{attrs:{id:"★1-1-db接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★1-1-db接続"}},[t._v("#")]),t._v(" ★1-1 DB接続")]),t._v(" "),s("p",[t._v("PostgreSQLデータベースに接続し、SQLを発行するためには「psql」というツールを利用します。"),s("br"),t._v("\n OSユーザ「postgres」にスイッチ後、データベースに接続してみます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("su - postgres\npsql -h localhost -p 5432 -d postgres -U postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(357),alt:""}}),s("br"),t._v("\n※プロンプトが「postgres=#」に変更されることを確認します。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★1-2-データベース確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★1-2-データベース確認"}},[t._v("#")]),t._v(" ★1-2 データベース確認")]),t._v(" "),s("p",[t._v("以下コマンド(エンマーク 英小文字のエル プラス)を実行します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\l+\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(358),alt:""}})]),t._v(" "),s("p",[t._v("現時点ではデータベースが3つ表示されています。"),s("br"),t._v("\n イメージ図としては以下(グレーの四角がデータベース)です。"),s("br"),t._v(" "),s("img",{attrs:{src:a(359),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_2-ユーザ-ロール-を作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-ユーザ-ロール-を作成してみよう"}},[t._v("#")]),t._v(" 2. ユーザ(ロール)を作成してみよう")]),t._v(" "),s("h3",{attrs:{id:"★2-1-ユーザ作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★2-1-ユーザ作成"}},[t._v("#")]),t._v(" ★2-1 ユーザ作成")]),t._v(" "),s("p",[t._v("デフォルトで作成されているユーザ「postgres」以外に以下の3ユーザを作成します。")]),t._v(" "),s("ul",[s("li",[t._v("ユーザ「user01」を作成します")]),t._v(" "),s("li",[t._v("ユーザ「user02」を作成します")]),t._v(" "),s("li",[t._v("スーパーユーザ「suser01」を作成します")])]),t._v(" "),s("p",[t._v("作成後は以下のようなイメージ(緑色の丸枠がユーザ)となります。")]),t._v(" "),s("p",[s("img",{attrs:{src:a(360),alt:""}})]),t._v(" "),s("p",[t._v("「user01」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create role user01 with login password 'user01'; \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("「user02」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" create user user02 with password 'user02';\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("「suser01」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" create role suser01 with superuser login password 'suser01';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※全て「CREATE ROLE」と表示されることを確認します。"),s("br"),t._v("\n※作成後、スーパーユーザ(suser01)でログインしなおしましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" \\connect - suser01 \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※PostgreSQLにおいて「ユーザ」と「ロール」は厳密には異なるため、上記のように2種類のコマンドが存在しますが、"),s("br"),t._v("\n 今回は「ユーザ」と「ロール」は同じものであると考えましょう。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_3-データベースを作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-データベースを作成してみよう"}},[t._v("#")]),t._v(" 3. データベースを作成してみよう")]),t._v(" "),s("p",[t._v("「create database」文を利用しデータベースを作成します。"),s("br"),t._v("\n ここでは、データベース名を「db_world」と指定し、template0を使用してデータベースを作成しています。"),s("br"),t._v("\n ※「public」スキーマも同時に作成されます。 (スキーマは後述しますが、「public」スキーマは全ユーザが自由に使えるスキーマです)")]),t._v(" "),s("p",[s("img",{attrs:{src:a(361),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★3-1-データベースの作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★3-1-データベースの作成"}},[t._v("#")]),t._v(" ★3-1 データベースの作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create database db_world owner = suser01 template = template0 encoding = 'UTF8' lc_collate = 'en_US.utf8' lc_ctype = 'en_US.utf8';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※「CREATE DATABASE」と表示されることを確認します。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★3-2-データベースへの接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★3-2-データベースへの接続"}},[t._v("#")]),t._v(" ★3-2 データベースへの接続")]),t._v(" "),s("p",[t._v("次STEPの準備として、作成したデータベース(db_world)にスーパーユーザ(suser01)で接続します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\connect db_world suser01 \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("br"),t._v(" "),s("h2",{attrs:{id:"_4-スキーマを作成し権限を付与してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-スキーマを作成し権限を付与してみよう"}},[t._v("#")]),t._v(" 4. スキーマを作成し権限を付与してみよう")]),t._v(" "),s("p",[t._v("データベース内にスキーマ(青色の四角枠)を作成し、ユーザに利用権限(オレンジの矢印)を付与します。"),s("br"),t._v("\n スキーマとは、テーブルやインデックスといったオブジェクトを配置する領域です。"),s("br"),t._v("\n ※「public」スキーマはDB作成時に作られており、テーブル等の作成時にスキーマ名を省略するとこの領域に配置されます。")]),t._v(" "),s("p",[s("img",{attrs:{src:a(362),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★4-1-スキーマの作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★4-1-スキーマの作成"}},[t._v("#")]),t._v(" ★4-1 スキーマの作成")]),t._v(" "),s("p",[t._v("以下の2つのスキーマを作成してみましょう。\n 以下の例では2つのスキーマの所有者に「suser01」を指定しています。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create schema sch_jpn authorization suser01;\t\ncreate schema sch_usa authorization suser01;\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("※「CREATE SCHEMA」と表示されることを確認してください。")]),t._v(" "),s("h3",{attrs:{id:"★4-2-権限付与"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★4-2-権限付与"}},[t._v("#")]),t._v(" ★4-2 権限付与")]),t._v(" "),s("p",[t._v("所有者以外がスキーマにオブジェクトを配置するためには権限が必要です。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("grant all privileges on database db_world to user01;\t\ngrant all privileges on schema sch_jpn to user01;\t\ngrant all privileges on schema sch_jpn to user02;\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("※「GRANT」と表示されることを確認してください。"),s("br"),t._v("\n  この権限の追加により")]),t._v(" "),s("ul",[s("li",[t._v("「user01」は「db_world」データベース、「sch_jpn」スキーマ内への全権限を有します。")]),t._v(" "),s("li",[t._v("「user02」は「sch_jpn」スキーマ内への全権限を有します。")])]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_5-テーブルを作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-テーブルを作成してみよう"}},[t._v("#")]),t._v(" 5. テーブルを作成してみよう")]),t._v(" "),s("p",[t._v("上記にて作成した「sch_jpn」スキーマ内にテーブル(オレンジ色の四角枠)を作成します。"),s("br"),t._v(" "),s("img",{attrs:{src:a(363),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★5-1-テーブル作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★5-1-テーブル作成"}},[t._v("#")]),t._v(" ★5-1 テーブル作成")]),t._v(" "),s("p",[t._v("「user01」で接続し、テーブルを作成します。"),s("br"),t._v("\n 以下ではテーブル作成時に主キー(PRIMARY KEY)を作成しています。"),s("br"),t._v("\n 主キーを作成した列には同じ値とnullを挿入できなくなります。"),s("br"),t._v("\n ※スキーマ(sch_jpn)は必ず指定してください。省略してしまうと「public」スキーマに作成されます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\connect db_world user01\ncreate table sch_jpn.tbl_region(id_reg serial,reg_name varchar(40), PRIMARY KEY (id_reg));\ncreate table sch_jpn.tbl_pref(id_pref serial,pref_name varchar(40),id_reg int, PRIMARY KEY (id_pref));\ncreate table sch_jpn.tbl_food(id_fd serial,fd_name varchar(40),price int, PRIMARY KEY (id_fd));\ncreate table sch_jpn.tbl_proper(id_user serial,username varchar(40),id_pref int,id_fd int, PRIMARY KEY (id_user));\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("※「CREATE TABLE」と表示されることを確認してください。")]),t._v(" "),s("p",[t._v("※テーブルを削除するコマンドは「drop table <テーブル名>」となります。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_6-テーブルにデータを登録してみよう-insert-into-values"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-テーブルにデータを登録してみよう-insert-into-values"}},[t._v("#")]),t._v(" 6. テーブルにデータを登録してみよう(insert into ~ values~)")]),t._v(" "),s("h3",{attrs:{id:"★6-1-データの登録"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★6-1-データの登録"}},[t._v("#")]),t._v(" ★6-1 データの登録")]),t._v(" "),s("p",[t._v("上記で作成したテーブルにデータを登録します。"),s("br"),t._v("\n データを追加するコマンドはinsert文となります。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("insert into sch_jpn.tbl_region(reg_name) values ('hokkaido');\ninsert into sch_jpn.tbl_region(reg_name) values ('tohoku');\ninsert into sch_jpn.tbl_region(reg_name) values ('kanto');\ninsert into sch_jpn.tbl_region(reg_name) values ('chubu');\ninsert into sch_jpn.tbl_region(reg_name) values ('kinki');\ninsert into sch_jpn.tbl_region(reg_name) values ('shikoku');\ninsert into sch_jpn.tbl_region(reg_name) values ('kyushu');\n\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('hokkaido',1);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('yamanashi',4);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('osaka',5);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('nagasaki',7);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('tokyo',3);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('chiba',3);\n\ninsert into sch_jpn.tbl_food(fd_name,price) values ('hamburger',500);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('ramen',1500);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('takoyaki',800);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('gyoza',350);\n\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('suzuki',1,1);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('satou',2,4);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('tanaka',3,2);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('ito',4,3);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('watanabe',5,4);\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br")])]),s("p",[t._v("※全て「INSERT 0 1」と表示されることを確認してください。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_7-データを参照してみよう-select-from"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_7-データを参照してみよう-select-from"}},[t._v("#")]),t._v(" 7. データを参照してみよう(select ~ from ~)")]),t._v(" "),s("h3",{attrs:{id:"★7-1-データの参照"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-1-データの参照"}},[t._v("#")]),t._v(" ★7-1 データの参照")]),t._v(" "),s("p",[t._v("テーブルに登録されているデータを参照します。データはSELECT文にて参照します。"),s("br"),t._v("\n ※「*」を指定するとテーブルのカラム(列)全てを指定したことと同義になります。")]),t._v(" "),s("p",[t._v("〇7-1-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_region;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_reg | reg_name\n--------+----------\n 1 | hokkaido\n 2 | tohoku\n 3 | kanto\n 4 | chubu\n 5 | kinki\n 6 | shikoku\n 7 | kyushu\n(7 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-2. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_pref;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-2. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_pref | pref_name | id_reg\n---------+-----------+--------\n 1 | hokkaido | 1\n 2 | yamanashi | 4\n 3 | osaka | 5\n 4 | nagasaki | 7\n 5 | tokyo | 3\n 6 | chiba | 3\n(6 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-3. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_food;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-3. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_fd | fd_name | price\n-------+-----------+-------\n 1 | hamburger | 500\n 2 | ramen | 1500\n 3 | takoyaki | 800\n 4 | gyoza | 350\n(4 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-4. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_proper;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-4. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_user | username | id_pref | id_fd\n---------+----------+---------+-------\n 1 | suzuki | 1 | 1\n 2 | satou | 2 | 4\n 3 | tanaka | 3 | 2\n 4 | ito | 4 | 3\n 5 | watanabe | 5 | 4\n(5 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("hr"),t._v(" "),s("h3",{attrs:{id:"★7-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-2"}},[t._v("#")]),t._v(" ★7-2")]),t._v(" "),s("p",[t._v("テーブルから条件を指定 (where句)してデータを抽出します。")]),t._v(" "),s("p",[t._v("〇7-2-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_pref where id_reg=3;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-2-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_pref | pref_name | id_reg\n---------+-----------+--------\n 5 | tokyo | 3\n 6 | chiba | 3\n(2 rows)\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★7-3-複数のテーブルからのデータ参照"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-3-複数のテーブルからのデータ参照"}},[t._v("#")]),t._v(" ★7-3 複数のテーブルからのデータ参照")]),t._v(" "),s("p",[t._v("複数のテーブルを結合しデータを抽出します。")]),t._v(" "),s("p",[t._v("〇7-3-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select\n pp.username,\n pr.pref_name,\n rg.reg_name,\n fd.fd_name\nfrom\n sch_jpn.tbl_region rg,\n sch_jpn.tbl_pref pr,\n sch_jpn.tbl_food fd,\n sch_jpn.tbl_proper pp\nwhere\n pp.id_pref=pr.id_pref and\n pp.id_fd=fd.id_fd and\n pr.id_reg=rg.id_reg\nORDER BY\npp.username\n;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br")])]),s("p",[t._v("●7-3-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" username | pref_name | reg_name | fd_name\n----------+-----------+----------+-----------\n ito | nagasaki | kyushu | takoyaki\n satou | yamanashi | chubu | gyoza\n suzuki | hokkaido | hokkaido | hamburger\n tanaka | osaka | kinki | ramen\n watanabe | tokyo | kanto | gyoza\n(5 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("h2",{attrs:{id:"_8-データを更新してみよう-update-set"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_8-データを更新してみよう-update-set"}},[t._v("#")]),t._v(" 8. データを更新してみよう(update ~ set ~)")]),t._v(" "),s("h3",{attrs:{id:"★8-1-データの更新"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★8-1-データの更新"}},[t._v("#")]),t._v(" ★8-1 データの更新")]),t._v(" "),s("p",[t._v("データを変更するには「update」文を使用します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("update sch_jpn.tbl_pref set id_reg=4 where id_pref=2;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◆変更されているか確認してみよう。"),s("br"),t._v("\n  ⇒ 上記で使用したSELECT文を使い「tbl_pref」を参照してください。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_9-データを削除してみよう-delete-from"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_9-データを削除してみよう-delete-from"}},[t._v("#")]),t._v(" 9. データを削除してみよう(delete from ~)")]),t._v(" "),s("h3",{attrs:{id:"★9-1-データの削除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★9-1-データの削除"}},[t._v("#")]),t._v(" ★9-1 データの削除")]),t._v(" "),s("p",[t._v("データを削除するには「delete」文を使用します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("delete from sch_jpn.tbl_food where fd_name='ramen';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◆削除されているか確認してみよう。"),s("br"),t._v("\n  ⇒ 上記で使用したSELECT文を使い「tbl_food」を参照してください。")]),t._v(" "),s("br"),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("h1",{attrs:{id:"演習問題"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#演習問題"}},[t._v("#")]),t._v(" 演習問題")]),t._v(" "),s("h3",{attrs:{id:"問1-自分の好きな食べ物を「tbl-food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl-proper」テーブルに登録してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問1-自分の好きな食べ物を「tbl-food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl-proper」テーブルに登録してください"}},[t._v("#")]),t._v(" 問1)自分の好きな食べ物を「tbl_food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl_proper」テーブルに登録してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: insert into ~ values ~ \n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問2-問1で追加したデータを参照してください-2テーブルを確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問2-問1で追加したデータを参照してください-2テーブルを確認してください"}},[t._v("#")]),t._v(" 問2)問1で追加したデータを参照してください(2テーブルを確認してください)")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: select ~ from ~ where ~\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問3-「tbl-proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問3-「tbl-proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください"}},[t._v("#")]),t._v(" 問3)「tbl_proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: update ~ set ~\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問4-「tbl-food」から「takoyaki」のみを削除し、確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問4-「tbl-food」から「takoyaki」のみを削除し、確認してください"}},[t._v("#")]),t._v(" 問4)「tbl_food」から「takoyaki」のみを削除し、確認してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: delete from ~ where ~\n")])])]),s("br"),t._v(" "),s("p",[t._v("▼▼▼▼▼▼▼▼▼▼▼▼▼以降、時間がある人向け▼▼▼▼▼▼▼▼▼▼▼▼▼")]),t._v(" "),s("h2",{attrs:{id:"a-バックアップ"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#a-バックアップ"}},[t._v("#")]),t._v(" A.バックアップ")]),t._v(" "),s("h3",{attrs:{id:"★a-1-データベース-バックアップ準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-1-データベース-バックアップ準備"}},[t._v("#")]),t._v(" ★A-1. データベース バックアップ準備")]),t._v(" "),s("p",[t._v("バックアップデータの保管先へ移動します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("su - postgres\t\ncd /tmp\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★a-2-データベースのバックアップ"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-データベースのバックアップ"}},[t._v("#")]),t._v(" ★A-2. データベースのバックアップ")]),t._v(" "),s("p",[t._v("ここでは、2通りのバックアップを試してみます。")]),t._v(" "),s("h4",{attrs:{id:"★a-2-1-plain形式での出力-人間が見て分かるような結果が出力されます"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-1-plain形式での出力-人間が見て分かるような結果が出力されます"}},[t._v("#")]),t._v(" ★A-2-1 plain形式での出力\t(人間が見て分かるような結果が出力されます)")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("pg_dump -U suser01 -d db_world --format=p --create --file db_world_db.sql\n\ncat db_world_db.sql\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h4",{attrs:{id:"★a-2-2-バイナリ形式での出力"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-2-バイナリ形式での出力"}},[t._v("#")]),t._v(" ★A-2-2 バイナリ形式での出力")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("pg_dump -U suser01 -d db_world --format=c --create --file db_world_db.custom\n\nls -l\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("◎出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("total 20\n-rw-r--r-- 1 postgres postgres 9710 Jul 10 12:00 db_world_db.custom\n-rw-r--r-- 1 postgres postgres 7561 Jul 10 11:59 db_world_db.sql\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("br"),t._v(" "),s("h2",{attrs:{id:"b-リストア"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#b-リストア"}},[t._v("#")]),t._v(" B.リストア")]),t._v(" "),s("h3",{attrs:{id:"★b-1-データベース削除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★b-1-データベース削除"}},[t._v("#")]),t._v(" ★B-1. データベース削除")]),t._v(" "),s("p",[t._v("データベースが破損したという仮定で、データベースを削除します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("psql -h localhost -p 5432 -d postgres -U postgres\n\n\\l\ndrop database db_world;\n\\l\n\n\\q\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★b-2-データベースをリストア"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★b-2-データベースをリストア"}},[t._v("#")]),t._v(" ★B-2. データベースをリストア")]),t._v(" "),s("p",[t._v("データベースが削除されているため、「db_world」データベースを作成し、"),s("br"),t._v("\n 「db_world_db.custom」を使ってリストアします。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("createdb --template=template0 --encoding='UTF8' --lc-collate='en_US.utf8' --lc-ctype='en_US.utf8' db_world\n\npg_restore -v -c -d db_world /tmp/db_world_db.custom\n\npsql -h localhost -p 5432 -d postgres -U postgres\n\\l\n\\q\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("この操作にてバックアップ取得時の状態へ復旧します。")]),t._v(" "),s("p",[t._v("※この他にもバックアップ取得時点ではなく、障害発生直前にまでリカバリできる"),s("br"),t._v("\n  バックアップコマンド(pg_basebackup)も存在しますがここでは割愛します。")]),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("h1",{attrs:{id:"postgresql環境の停止について"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#postgresql環境の停止について"}},[t._v("#")]),t._v(" PostgreSQL環境の停止について")]),t._v(" "),s("p",[t._v("Docker runコマンド実行の際に -d optionをつけている(back ground実行)ため、"),s("br"),t._v("\n★0-3 コンテナ接続"),s("br"),t._v("\nで 開いていた bash で exit してもPostgreSQL(コンテナ)環境は終了しません。")]),t._v(" "),s("p",[t._v("演習が終わりましたらstopコマンドにて停止させてください。"),s("br"),t._v("\npsコマンドにてstatus列 が Exited になっていれば停止となります。"),s("br"),t._v("\n※再度利用する際には docker start some-postgres にて起動可能させます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker stop some-postgres\n\ndocker ps -a\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("以上")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/11.b7cad954.js b/assets/js/11.b7cad954.js deleted file mode 100644 index 7bd85ef1..00000000 --- a/assets/js/11.b7cad954.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{353:function(t,s,a){t.exports=a.p+"assets/img/docker01.9c3fed93.jpg"},354:function(t,s){t.exports="data:image/jpeg;base64,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"},355:function(t,s){t.exports="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAYANgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzSitzw+lg1jrU19p6XZtbRJ4cyuhV/OjTB2nlSJPmGM4HBU81Ikeli3vdZisvNt4ZLeFLKZmCCSWN2ckq24opjcKNwJBUknBDerzHHY5+ium/smy2f2v5H+jf2d/aH2Le23d9p+z+Xvzu2bvm/vbfl3Z+eqtwLJLWx1uPTbcRzTTW8lgzymHdGsZ3A794BEo43HlSc4O0HMFjJ+x3P237F9nm+1+Z5XkbDv35xt29c54x1zV270V7e2eaG9tLzycfaUtmZjb5OBuJUBhnjchZc45+Zc9TqF1DN8SNY8qwt7aW1bU5BNC0hd5EilZJDuYgMrKGBULg89hizq9pZ6d4Y1eCBLSONPOt4JIyhkmh8+0aFnYcsXCTSLnqu4qAgGJ53oPlOTu/DV5ZRuk0kIv4oxNNp+HE8UZXduIKhThSGIViwBJIG1ttqLwlvuDaya7pcN4kLTS28i3G+ELGZHVsREBlUHK5JBBHXirMLXL3d9DeQ6jF4l+xTmW41CUvlBES67GUMpMIZQWLjngDIZM+KaWLw5qeoXEjyXOpzLah5GLGRVZZpmJ67gwg5PUO3U8qXYWRh0V1lhocMej2Ny9pp139vjaR2utTjtXhUSPHiNWkXn5Cd7K65IG35W3Vp7Gw0KCW5MdvrCtf3FnC0jOsRSIIfMHluCS3mLj5sAA/eyCtcyFY5yiustLTQ4rd7hEtJLeSTAn1Y3ARf3aN5SeRhndSzh227cBCNu8A1pdGtLHX/EMbB57XRmkZIpGwZgs6xKGZcYGXBOMEgEArnIOZBYwrS0nvrlLe3TfI+cDIAAAySSeAAASScAAEnAFWr7SjaQLcQXlvfWpbY09tv2o+CQrB1VgSASDjBwcE7WxraW1pc6pa3dgsNnIY7n7ZZhXkjECQkuV3NuO+MyLt35DKTuUMNtxLCDxHZRWfhi1mtEudRiS6tZ2MuyRhL5RWQDJjRFlJyoIycl+NqcrMLHNT6Xc2+kWepyrtt7ySWOHIILeXt3MOMEZfGQeqsO1WZvD88MEn+k273sKl57BS3nwqBliwK7SVHLKGLLzuA2tt6PxZYamfC9lIdI1G1sLO9uI4VuLZkMUGy3VGcYwpchiSOGcuR1p4toX8VaxqNzcPbXt1aX850yW3kWeF3tpWIfcAu0AnDAkn5flXJ2rn0uPlOZh8PzzQR/6TbpezKHgsGLefMpGVKgLtBYcqpYM3G0Hcu7JrsoP+Sl+Gv+4T/wCiYKhsNDhj0exuXtNOu/t8bSO11qcdq8KiR48Rq0i8/ITvZXXJA2/K2581twsYdjpRu4GuJ7y3sbUNsWe537XfAJVQisxIBBJxgZGSNy5q3dpPY3L29wmyRMZGQQQRkEEcEEEEEZBBBGQa3dbtorLw9bWkFyl1FBq9/Gk6Y2yqqW4DDBPBAz1PWrM91q9l4ysLjQlmbUk06z8kQw+a3NnGGwuDn5Se1HMxWOTq7c2H2XTLG6eX95d+Y6xbekSnaHznuwkGOo2Z6EUaTYf2nqcNqZfKjO55pdu7yolBZ3xnnaqscDk4wOa3/Dzz+IfiJYzQ6b51t9oiRrYwi4WG1BWMK2VIIVNq7yM8A5zzTk7AkY2q6Hc6R5n2iSFtl7PZHyyT88OzceQODvGO/XgVmV2XjW41s6XoqavZ/Z3uY5bqbfYJAz3BmkVmJCA5KCLI7/KT2NcbRFtq7BqzCiiiqEFFFFAGhp+qnT7PULYWdvOL6EQO8u/dGoYN8u1gM7lU8g/dHYkFlhqL2PmRtBDdW0uPNtp92xyM7T8pDAjJwQQcEjoxBKKVkFyb+3Ln7b5/lw+R5fkfY8HyfJzny8ZzjPOc7t3z7t/zVDf6i995cawQ2ttFnyraDdsQnG4/MSxJwMkknAA6KACiiyC5fn8VX0k6XEMVvbXX2tL2aeJWLT3CElZGDFlBBdzhQq/MeOBitd3+ntbPHY6X9mkmx5zyTecFwc7YgVBQZ9SzYAG7BbcUUcqC7JrvxLeXsbvNHCb+WMQzahlzPLGF27SSxUZUBSVUMQCCTubdnvfSyaXBp5VPKgmknUgHcWdUU59sRrj6miihJILlq01p7e2SGaytLzyc/ZnuVZjb5OTtAYBhnna4Zc54+Zslvrcyeat9bw6nHLIZil40hxKfvOGVlYE9+cNgZBKqQUUWQXJl8SXLRst5a2l6RIZYDcRnEDlVXKopCkYSMBGDIAgAUDIJeeJLm81qfUmtbRPtO4T20cZEUwZt7B+dxyxzktlTt2ldq4KKOVBdkMmuXP2mCW1jhs4rfd5VvACY13DD5Dli+4cNuLZGFPygAMvtVN3AtvBZ29jaht7QW2/a74IDMXZmJAJAGcDJwBubJRRZBcJtVM2hW2lfY7dVt5nnE67/ADGZwA2cttxhUHCj7o9Tmzd+Jby9jd5o4TfyxiGbUMuZ5Ywu3aSWKjKgKSqhiAQSdzbiijlQXYyHxBPDBH/o1u97CoSC/YN58KgYUKQ20lRwrFSy8bSNq7WWmtPb2yQzWVpeeTn7M9yrMbfJydoDAMM87XDLnPHzNkoo5UF2Fvrcyeat9bw6nHLIZil40hxKfvOGVlYE9+cNgZBKqRD/AGtqA1P+0o7yaG8H3ZoW8soMbQF242gL8oAwAOBxRRRZBcLa/wDsumX1qkX7y78tGl3dIlO4pjHdhGc9Rsx0Jo0u/wD7Nu3n8rzN9vPBt3Yx5kTx56dt+cd8dqKKLBcNUv8A+0rtJ/K8vZbwQbd2c+XEkeenfZnHbPeqVFFPYAooooAKKKKAP//Z"},356:function(t,s){t.exports="data:image/jpeg;base64,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"},357:function(t,s){t.exports="data:image/jpeg;base64,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"},358:function(t,s,a){t.exports=a.p+"assets/img/docker06.f94651f1.jpg"},359:function(t,s,a){t.exports=a.p+"assets/img/DB00.3fdfd46b.jpg"},360:function(t,s,a){t.exports=a.p+"assets/img/DB01.e9d2dca0.jpg"},361:function(t,s,a){t.exports=a.p+"assets/img/DB02.deae098c.jpg"},362:function(t,s,a){t.exports=a.p+"assets/img/DB03.67543a21.jpg"},363:function(t,s,a){t.exports=a.p+"assets/img/DB04.195ebfdf.jpg"},514:function(t,s,a){"use strict";a.r(s);var e=a(10),r=Object(e.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"リレーショナルdbを触ってみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#リレーショナルdbを触ってみる"}},[t._v("#")]),t._v(" リレーショナルDBを触ってみる")]),t._v(" "),s("hr"),t._v(" "),s("h2",{attrs:{id:"事前準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#事前準備"}},[t._v("#")]),t._v(" <事前準備>")]),t._v(" "),s("ul",[s("li",[t._v("Dockerがインストールされていること")]),t._v(" "),s("li",[t._v("PowerShellが利用できる状態であること")]),t._v(" "),s("li",[t._v("インターネットに接続できていること")])]),t._v(" "),s("h1",{attrs:{id:"postgresqlについて"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#postgresqlについて"}},[t._v("#")]),t._v(" PostgreSQLについて")]),t._v(" "),s("h3",{attrs:{id:"呼び方"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#呼び方"}},[t._v("#")]),t._v(" 呼び方")]),t._v(" "),s("p",[t._v("「ポストグレス キューエル」らしいのですが、この呼び方している人は少ないように感じます。"),s("br"),t._v("\nよく聞くのは「ポスグレ」、「ポストグレス」です。")]),t._v(" "),s("h3",{attrs:{id:"日本postgresqlユーザ会"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#日本postgresqlユーザ会"}},[t._v("#")]),t._v(" 日本PostgreSQLユーザ会")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://www.postgresql.jp/",target:"_blank",rel:"noopener noreferrer"}},[t._v("日本PostgreSQLユーザ会"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("日本国内でPostgreSQLデータベースを使用するユーザーのコミュニティおよび組織です。")]),t._v(" "),s("li",[t._v("このユーザ会は、PostgreSQLに関心を持つ人々が情報共有や交流を行い、技術的な知識を向上させることを目的としています。")])]),t._v(" "),s("h3",{attrs:{id:"バージョン体系-超抜粋"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#バージョン体系-超抜粋"}},[t._v("#")]),t._v(" バージョン体系(超抜粋)")]),t._v(" "),s("p",[t._v("※8.0よりも前のバージョン(6.0や7.0)については省略します。")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",{staticStyle:{"text-align":"right"}},[t._v("メジャーバージョン")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("リリース日")]),t._v(" "),s("th",{staticStyle:{"text-align":"right"}},[t._v("最新マイナー版")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("最新版リリース日")]),t._v(" "),s("th",{staticStyle:{"text-align":"center"}},[t._v("サポート期限")])])]),t._v(" "),s("tbody",[s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("8.0")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2005/11/8")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("8.0.26")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/4")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/1")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("8.1.x~8.4.x")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("9.0")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/9/20")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("9.0.23")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2015/10/8")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2010/10/8")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("9.1.x~9.6.x")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("省略")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("10")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2017/10/5")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("10.22")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/8/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/11/10")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2018/10/18")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("11.20")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/5/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/11/9")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("12")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2019/10/3")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("12.15")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/5/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2024/11/14")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("13")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2020/9/24")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("13.11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/5/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2025/11/13")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("14")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2021/9/30")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("14.8")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/5/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2026/11/12")])]),t._v(" "),s("tr",[s("td",{staticStyle:{"text-align":"right"}},[t._v("15")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2022/10/13")]),t._v(" "),s("td",{staticStyle:{"text-align":"right"}},[t._v("15.3")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("2023/5/11")]),t._v(" "),s("td",{staticStyle:{"text-align":"center"}},[t._v("-")])])])]),t._v(" "),s("p",[t._v("※バージョン体系がPostgreSQL10より変更されました。")]),t._v(" "),s("p",[t._v("Postgresql 10以前 ⇒  "),s("span",{staticStyle:{"font-size":"200%",color:"red"}},[s("strong",[t._v("9.0")])]),t._v(" ."),s("span",{staticStyle:{"font-size":"200%",color:"blue"}},[t._v("23")]),s("br"),t._v(" "),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("9.0の部分がメジャーバージョン")]),t._v("で"),s("span",{staticStyle:{"font-size":"100%",color:"blue"}},[t._v("23がマイナーバージョン")]),t._v("となります。"),s("br"),t._v(" "),s("br"),t._v("\n   Postgresql 10以降 ⇒  "),s("span",{staticStyle:{"font-size":"200%",color:"red"}},[s("strong",[t._v("10")])]),t._v(" ."),s("span",{staticStyle:{"font-size":"200%",color:"blue"}},[t._v("22")]),s("br"),t._v(" "),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("10の部分がメジャーバージョン")]),t._v("で"),s("span",{staticStyle:{"font-size":"100%",color:"blue"}},[t._v("22がマイナーバージョン")]),t._v(" となります。")]),t._v(" "),s("h3",{attrs:{id:"ライセンス"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#ライセンス"}},[t._v("#")]),t._v(" ライセンス")]),t._v(" "),s("p",[t._v("PostgreSQLは、"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("オープンソースのリレーショナルデータベース")]),t._v("管理システムです。"),s("br"),t._v("\nそのライセンスは、PostgreSQL Global Development Group(PGDG)によって開発されたもので以下の2つのライセンスオプションが提供されています。")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("PostgreSQLライセンス(PostgreSQL License\nこれは、PostgreSQLプロジェクトが採用している独自のライセンスです。\nこのライセンスは、商用利用や非商用利用、修正や再配布を含むあらゆる使用形態に対して、\n自由かつ"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("無償で利用することを許可しています。")]),t._v("また、ソースコードの利用や変更、派生物の作成、\nバイナリ形式での再配布なども可能です。そのため、PostgreSQLを自由に使用し、変更や拡張を行い、\nプロジェクトや製品に組み込むことができます。")])]),t._v(" "),s("li",[s("p",[t._v("MIT(マサチューセッツ工科大学)ライセンス\nPostgreSQLプロジェクトは、PostgreSQLライセンスに加えて、一部のコンポーネントについてはMITライセンスも採用しています。\nMITライセンスは、商用利用や非商用利用、修正や再配布を含むあらゆる使用形態に対して、"),s("span",{staticStyle:{"font-size":"100%",color:"red"}},[t._v("自由かつ無償で利用することを許可")]),t._v("しています。\nただし、著作権表示および本許諾表示をソフトウェアのすべての複製または重要な部分に記載しなければならず、作者または著作権者は、ソフトウェアに関してなんら責任を負わない。")])])]),t._v(" "),s("h1",{attrs:{id:"ハンズオン研修-【データベースに触れてみよう】"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#ハンズオン研修-【データベースに触れてみよう】"}},[t._v("#")]),t._v(" ハンズオン研修 【データベースに触れてみよう】")]),t._v(" "),s("h2",{attrs:{id:"_0-postgresql環境準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-postgresql環境準備"}},[t._v("#")]),t._v(" 0. PostgreSQL環境準備")]),t._v(" "),s("p",[t._v("本演習にて入力するコマンドはおおきく分けて以下の3つにわかれているため、入力する場所には注意する必要があります。")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("1.Linux環境 【 $ 表示のプロンプト】"),s("br"),t._v("\n →  ★0-1、★0-2 、★0-3 での入力先となります。")])]),t._v(" "),s("li",[s("p",[t._v("2.コンテナ環境 【 root@xxx から始まるプロンプト】"),s("br"),t._v("\n →  ★0-4 ★1-1、及び★A-1、★A-2、★B-1先頭行、★B-2 での入力先となります。")])]),t._v(" "),s("li",[s("p",[t._v("3.PostgreSQL環境 【 postgres=# から始まるプロンプト】"),s("br"),t._v("\n →  ★1-2~演習問題まで及び★B-1drop文 の入力先となります。")])])]),t._v(" "),s("p",[t._v("※出力イメージと異なるような結果が表示された際には入力場所をご確認ください。")]),t._v(" "),s("h3",{attrs:{id:"★0-1-postgresql環境のダウンロード"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-1-postgresql環境のダウンロード"}},[t._v("#")]),t._v(" ★0-1 PostgreSQL環境のダウンロード")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、PostgreSQL環境をダウンロードします。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker pull postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ\n"),s("img",{attrs:{src:a(353),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-2-コンテナ起動"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-2-コンテナ起動"}},[t._v("#")]),t._v(" ★0-2 コンテナ起動")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、コンテナ(PostgreSQLも起動します)環境を起動させます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker run --name some-postgres -e POSTGRES_PASSWORD=postgres -d postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(354),alt:""}}),s("br"),t._v("\n※正常に起動すると上記のような64文字の文字列(値は各自で異なります)が表示されます。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-3-コンテナ接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-3-コンテナ接続"}},[t._v("#")]),t._v(" ★0-3 コンテナ接続")]),t._v(" "),s("p",[t._v("以下のコマンドを入力し、コンテナに接続します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker exec -it some-postgres /bin/bash\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(355),alt:""}}),s("br"),t._v("\n ※接続に成功すると上記のような最後に「#」が付いた状態で表示されます。"),s("br"),t._v("\n ※「root@」以降の文字列は各自で異なります。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★0-4-ロケールの確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★0-4-ロケールの確認"}},[t._v("#")]),t._v(" ★0-4 ロケールの確認")]),t._v(" "),s("p",[t._v("本講義で使用する言語「en_US.utf8」が表示されることを確認します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("locale -a\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(356),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_1-データベースへ接続してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-データベースへ接続してみよう"}},[t._v("#")]),t._v(" 1. データベースへ接続してみよう")]),t._v(" "),s("h3",{attrs:{id:"★1-1-db接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★1-1-db接続"}},[t._v("#")]),t._v(" ★1-1 DB接続")]),t._v(" "),s("p",[t._v("PostgreSQLデータベースに接続し、SQLを発行するためには「psql」というツールを利用します。"),s("br"),t._v("\n OSユーザ「postgres」にスイッチ後、データベースに接続してみます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("su - postgres\npsql -h localhost -p 5432 -d postgres -U postgres\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(357),alt:""}}),s("br"),t._v("\n※プロンプトが「postgres=#」に変更されることを確認します。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★1-2-データベース確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★1-2-データベース確認"}},[t._v("#")]),t._v(" ★1-2 データベース確認")]),t._v(" "),s("p",[t._v("以下コマンド(エンマーク 英小文字のエル プラス)を実行します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\l+\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◎出力イメージ"),s("br"),t._v(" "),s("img",{attrs:{src:a(358),alt:""}})]),t._v(" "),s("p",[t._v("現時点ではデータベースが3つ表示されています。"),s("br"),t._v("\n イメージ図としては以下(グレーの四角がデータベース)です。"),s("br"),t._v(" "),s("img",{attrs:{src:a(359),alt:""}})]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_2-ユーザ-ロール-を作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-ユーザ-ロール-を作成してみよう"}},[t._v("#")]),t._v(" 2. ユーザ(ロール)を作成してみよう")]),t._v(" "),s("h3",{attrs:{id:"★2-1-ユーザ作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★2-1-ユーザ作成"}},[t._v("#")]),t._v(" ★2-1 ユーザ作成")]),t._v(" "),s("p",[t._v("デフォルトで作成されているユーザ「postgres」以外に以下の3ユーザを作成します。")]),t._v(" "),s("ul",[s("li",[t._v("ユーザ「user01」を作成します")]),t._v(" "),s("li",[t._v("ユーザ「user02」を作成します")]),t._v(" "),s("li",[t._v("スーパーユーザ「suser01」を作成します")])]),t._v(" "),s("p",[t._v("作成後は以下のようなイメージ(緑色の丸枠がユーザ)となります。")]),t._v(" "),s("p",[s("img",{attrs:{src:a(360),alt:""}})]),t._v(" "),s("p",[t._v("「user01」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create role user01 with login password 'user01'; \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("「user02」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" create user user02 with password 'user02';\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("「suser01」の作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" create role suser01 with superuser login password 'suser01';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※全て「CREATE ROLE」と表示されることを確認します。"),s("br"),t._v("\n※作成後、スーパーユーザ(suser01)でログインしなおしましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" \\connect - suser01 \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※PostgreSQLにおいて「ユーザ」と「ロール」は厳密には異なるため、上記のように2種類のコマンドが存在しますが、"),s("br"),t._v("\n 今回は「ユーザ」と「ロール」は同じものであると考えましょう。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_3-データベースを作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-データベースを作成してみよう"}},[t._v("#")]),t._v(" 3. データベースを作成してみよう")]),t._v(" "),s("p",[t._v("「create database」文を利用しデータベースを作成します。"),s("br"),t._v("\n ここでは、データベース名を「db_world」と指定し、template0を使用してデータベースを作成しています。"),s("br"),t._v("\n ※「public」スキーマも同時に作成されます。 (スキーマは後述しますが、「public」スキーマは全ユーザが自由に使えるスキーマです)")]),t._v(" "),s("p",[s("img",{attrs:{src:a(361),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★3-1-データベースの作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★3-1-データベースの作成"}},[t._v("#")]),t._v(" ★3-1 データベースの作成")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create database db_world owner = suser01 template = template0 encoding = 'UTF8' lc_collate = 'en_US.utf8' lc_ctype = 'en_US.utf8';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("※「CREATE DATABASE」と表示されることを確認します。")]),t._v(" "),s("br"),t._v(" "),s("h3",{attrs:{id:"★3-2-データベースへの接続"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★3-2-データベースへの接続"}},[t._v("#")]),t._v(" ★3-2 データベースへの接続")]),t._v(" "),s("p",[t._v("次STEPの準備として、作成したデータベース(db_world)にスーパーユーザ(suser01)で接続します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\connect db_world suser01 \n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("br"),t._v(" "),s("h2",{attrs:{id:"_4-スキーマを作成し権限を付与してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-スキーマを作成し権限を付与してみよう"}},[t._v("#")]),t._v(" 4. スキーマを作成し権限を付与してみよう")]),t._v(" "),s("p",[t._v("データベース内にスキーマ(青色の四角枠)を作成し、ユーザに利用権限(オレンジの矢印)を付与します。"),s("br"),t._v("\n スキーマとは、テーブルやインデックスといったオブジェクトを配置する領域です。"),s("br"),t._v("\n ※「public」スキーマはDB作成時に作られており、テーブル等の作成時にスキーマ名を省略するとこの領域に配置されます。")]),t._v(" "),s("p",[s("img",{attrs:{src:a(362),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★4-1-スキーマの作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★4-1-スキーマの作成"}},[t._v("#")]),t._v(" ★4-1 スキーマの作成")]),t._v(" "),s("p",[t._v("以下の2つのスキーマを作成してみましょう。\n 以下の例では2つのスキーマの所有者に「suser01」を指定しています。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("create schema sch_jpn authorization suser01;\t\ncreate schema sch_usa authorization suser01;\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("※「CREATE SCHEMA」と表示されることを確認してください。")]),t._v(" "),s("h3",{attrs:{id:"★4-2-権限付与"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★4-2-権限付与"}},[t._v("#")]),t._v(" ★4-2 権限付与")]),t._v(" "),s("p",[t._v("所有者以外がスキーマにオブジェクトを配置するためには権限が必要です。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("grant all privileges on database db_world to user01;\t\ngrant all privileges on schema sch_jpn to user01;\t\ngrant all privileges on schema sch_jpn to user02;\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("※「GRANT」と表示されることを確認してください。"),s("br"),t._v("\n  この権限の追加により")]),t._v(" "),s("ul",[s("li",[t._v("「user01」は「db_world」データベース、「sch_jpn」スキーマ内への全権限を有します。")]),t._v(" "),s("li",[t._v("「user02」は「sch_jpn」スキーマ内への全権限を有します。")])]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_5-テーブルを作成してみよう"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-テーブルを作成してみよう"}},[t._v("#")]),t._v(" 5. テーブルを作成してみよう")]),t._v(" "),s("p",[t._v("上記にて作成した「sch_jpn」スキーマ内にテーブル(オレンジ色の四角枠)を作成します。"),s("br"),t._v(" "),s("img",{attrs:{src:a(363),alt:""}})]),t._v(" "),s("h3",{attrs:{id:"★5-1-テーブル作成"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★5-1-テーブル作成"}},[t._v("#")]),t._v(" ★5-1 テーブル作成")]),t._v(" "),s("p",[t._v("「user01」で接続し、テーブルを作成します。"),s("br"),t._v("\n 以下ではテーブル作成時に主キー(PRIMARY KEY)を作成しています。"),s("br"),t._v("\n 主キーを作成した列には同じ値とnullを挿入できなくなります。"),s("br"),t._v("\n ※スキーマ(sch_jpn)は必ず指定してください。省略してしまうと「public」スキーマに作成されます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("\\connect db_world user01\ncreate table sch_jpn.tbl_region(id_reg serial,reg_name varchar(40), PRIMARY KEY (id_reg));\ncreate table sch_jpn.tbl_pref(id_pref serial,pref_name varchar(40),id_reg int, PRIMARY KEY (id_pref));\ncreate table sch_jpn.tbl_food(id_fd serial,fd_name varchar(40),price int, PRIMARY KEY (id_fd));\ncreate table sch_jpn.tbl_proper(id_user serial,username varchar(40),id_pref int,id_fd int, PRIMARY KEY (id_user));\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("※「CREATE TABLE」と表示されることを確認してください。")]),t._v(" "),s("p",[t._v("※テーブルを削除するコマンドは「drop table <テーブル名>」となります。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_6-テーブルにデータを登録してみよう-insert-into-values"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-テーブルにデータを登録してみよう-insert-into-values"}},[t._v("#")]),t._v(" 6. テーブルにデータを登録してみよう(insert into ~ values~)")]),t._v(" "),s("h3",{attrs:{id:"★6-1-データの登録"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★6-1-データの登録"}},[t._v("#")]),t._v(" ★6-1 データの登録")]),t._v(" "),s("p",[t._v("上記で作成したテーブルにデータを登録します。"),s("br"),t._v("\n データを追加するコマンドはinsert文となります。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("insert into sch_jpn.tbl_region(reg_name) values ('hokkaido');\ninsert into sch_jpn.tbl_region(reg_name) values ('tohoku');\ninsert into sch_jpn.tbl_region(reg_name) values ('kanto');\ninsert into sch_jpn.tbl_region(reg_name) values ('chubu');\ninsert into sch_jpn.tbl_region(reg_name) values ('kinki');\ninsert into sch_jpn.tbl_region(reg_name) values ('shikoku');\ninsert into sch_jpn.tbl_region(reg_name) values ('kyushu');\n\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('hokkaido',1);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('yamanashi',4);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('osaka',5);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('nagasaki',7);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('tokyo',3);\ninsert into sch_jpn.tbl_pref(pref_name,id_reg) values ('chiba',3);\n\ninsert into sch_jpn.tbl_food(fd_name,price) values ('hamburger',500);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('ramen',1500);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('takoyaki',800);\ninsert into sch_jpn.tbl_food(fd_name,price) values ('gyoza',350);\n\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('suzuki',1,1);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('satou',2,4);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('tanaka',3,2);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('ito',4,3);\ninsert into sch_jpn.tbl_proper(username,id_pref,id_fd) values ('watanabe',5,4);\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br")])]),s("p",[t._v("※全て「INSERT 0 1」と表示されることを確認してください。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_7-データを参照してみよう-select-from"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_7-データを参照してみよう-select-from"}},[t._v("#")]),t._v(" 7. データを参照してみよう(select ~ from ~)")]),t._v(" "),s("h3",{attrs:{id:"★7-1-データの参照"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-1-データの参照"}},[t._v("#")]),t._v(" ★7-1 データの参照")]),t._v(" "),s("p",[t._v("テーブルに登録されているデータを参照します。データはSELECT文にて参照します。"),s("br"),t._v("\n ※「*」を指定するとテーブルのカラム(列)全てを指定したことと同義になります。")]),t._v(" "),s("p",[t._v("〇7-1-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_region;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_reg | reg_name\n--------+----------\n 1 | hokkaido\n 2 | tohoku\n 3 | kanto\n 4 | chubu\n 5 | kinki\n 6 | shikoku\n 7 | kyushu\n(7 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-2. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_pref;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-2. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_pref | pref_name | id_reg\n---------+-----------+--------\n 1 | hokkaido | 1\n 2 | yamanashi | 4\n 3 | osaka | 5\n 4 | nagasaki | 7\n 5 | tokyo | 3\n 6 | chiba | 3\n(6 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-3. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_food;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-3. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_fd | fd_name | price\n-------+-----------+-------\n 1 | hamburger | 500\n 2 | ramen | 1500\n 3 | takoyaki | 800\n 4 | gyoza | 350\n(4 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br")])]),s("br"),t._v(" "),s("p",[t._v("〇7-1-4. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_proper;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-1-4. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_user | username | id_pref | id_fd\n---------+----------+---------+-------\n 1 | suzuki | 1 | 1\n 2 | satou | 2 | 4\n 3 | tanaka | 3 | 2\n 4 | ito | 4 | 3\n 5 | watanabe | 5 | 4\n(5 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("hr"),t._v(" "),s("h3",{attrs:{id:"★7-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-2"}},[t._v("#")]),t._v(" ★7-2")]),t._v(" "),s("p",[t._v("テーブルから条件を指定 (where句)してデータを抽出します。")]),t._v(" "),s("p",[t._v("〇7-2-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select * from sch_jpn.tbl_pref where id_reg=3;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("●7-2-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" id_pref | pref_name | id_reg\n---------+-----------+--------\n 5 | tokyo | 3\n 6 | chiba | 3\n(2 rows)\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★7-3-複数のテーブルからのデータ参照"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★7-3-複数のテーブルからのデータ参照"}},[t._v("#")]),t._v(" ★7-3 複数のテーブルからのデータ参照")]),t._v(" "),s("p",[t._v("複数のテーブルを結合しデータを抽出します。")]),t._v(" "),s("p",[t._v("〇7-3-1. 入力コマンド")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("select\n pp.username,\n pr.pref_name,\n rg.reg_name,\n fd.fd_name\nfrom\n sch_jpn.tbl_region rg,\n sch_jpn.tbl_pref pr,\n sch_jpn.tbl_food fd,\n sch_jpn.tbl_proper pp\nwhere\n pp.id_pref=pr.id_pref and\n pp.id_fd=fd.id_fd and\n pr.id_reg=rg.id_reg\nORDER BY\npp.username\n;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br")])]),s("p",[t._v("●7-3-1. 出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" username | pref_name | reg_name | fd_name\n----------+-----------+----------+-----------\n ito | nagasaki | kyushu | takoyaki\n satou | yamanashi | chubu | gyoza\n suzuki | hokkaido | hokkaido | hamburger\n tanaka | osaka | kinki | ramen\n watanabe | tokyo | kanto | gyoza\n(5 rows)\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("h2",{attrs:{id:"_8-データを更新してみよう-update-set"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_8-データを更新してみよう-update-set"}},[t._v("#")]),t._v(" 8. データを更新してみよう(update ~ set ~)")]),t._v(" "),s("h3",{attrs:{id:"★8-1-データの更新"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★8-1-データの更新"}},[t._v("#")]),t._v(" ★8-1 データの更新")]),t._v(" "),s("p",[t._v("データを変更するには「update」文を使用します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("update sch_jpn.tbl_pref set id_reg=4 where id_pref=2;\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◆変更されているか確認してみよう。"),s("br"),t._v("\n  ⇒ 上記で使用したSELECT文を使い「tbl_pref」を参照してください。")]),t._v(" "),s("br"),t._v(" "),s("h2",{attrs:{id:"_9-データを削除してみよう-delete-from"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_9-データを削除してみよう-delete-from"}},[t._v("#")]),t._v(" 9. データを削除してみよう(delete from ~)")]),t._v(" "),s("h3",{attrs:{id:"★9-1-データの削除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★9-1-データの削除"}},[t._v("#")]),t._v(" ★9-1 データの削除")]),t._v(" "),s("p",[t._v("データを削除するには「delete」文を使用します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("delete from sch_jpn.tbl_food where fd_name='ramen';\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("◆削除されているか確認してみよう。"),s("br"),t._v("\n  ⇒ 上記で使用したSELECT文を使い「tbl_food」 を参照してください。")]),t._v(" "),s("br"),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("h1",{attrs:{id:"演習問題"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#演習問題"}},[t._v("#")]),t._v(" 演習問題")]),t._v(" "),s("h3",{attrs:{id:"問1-自分の好きな食べ物を「tbl-food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl-proper」テーブルに登録してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問1-自分の好きな食べ物を「tbl-food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl-proper」テーブルに登録してください"}},[t._v("#")]),t._v(" 問1)自分の好きな食べ物を「tbl_food」テーブルに登録し、そのデータを使って自分の情報をプロパー「tbl_proper」テーブルに登録してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: insert into ~ values ~ \n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問2-問1で追加したデータを参照してください-2テーブルを確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問2-問1で追加したデータを参照してください-2テーブルを確認してください"}},[t._v("#")]),t._v(" 問2)問1で追加したデータを参照してください(2テーブルを確認してください)")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: select ~ from ~ where ~\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問3-「tbl-proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問3-「tbl-proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください"}},[t._v("#")]),t._v(" 問3)「tbl_proper」の中に存在している「tanaka」さんを「ikeda」さんに変更し、確認してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: update ~ set ~\n")])])]),s("br"),t._v(" "),s("h3",{attrs:{id:"問4-「tbl-food」から「takoyaki」のみを削除し、確認してください"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#問4-「tbl-food」から「takoyaki」のみを削除し、確認してください"}},[t._v("#")]),t._v(" 問4)「tbl_food」から「takoyaki」のみを削除し、確認してください")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",[s("code",[t._v("hint: delete from ~ where ~\n")])])]),s("br"),t._v(" "),s("p",[t._v("▼▼▼▼▼▼▼▼▼▼▼▼▼以降、時間がある人向け▼▼▼▼▼▼▼▼▼▼▼▼▼")]),t._v(" "),s("h2",{attrs:{id:"a-バックアップ"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#a-バックアップ"}},[t._v("#")]),t._v(" A.バックアップ")]),t._v(" "),s("h3",{attrs:{id:"★a-1-データベース-バックアップ準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-1-データベース-バックアップ準備"}},[t._v("#")]),t._v(" ★A-1. データベース バックアップ準備")]),t._v(" "),s("p",[t._v("バックアップデータの保管先へ移動します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("su - postgres\t\ncd /tmp\t\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★a-2-データベースのバックアップ"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-データベースのバックアップ"}},[t._v("#")]),t._v(" ★A-2. データベースのバックアップ")]),t._v(" "),s("p",[t._v("ここでは、2通りのバックアップを試してみます。")]),t._v(" "),s("h4",{attrs:{id:"★a-2-1-plain形式での出力-人間が見て分かるような結果が出力されます"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-1-plain形式での出力-人間が見て分かるような結果が出力されます"}},[t._v("#")]),t._v(" ★A-2-1 plain形式での出力\t(人間が見て分かるような結果が出力されます)")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("pg_dump -U suser01 -d db_world --format=p --create --file db_world_db.sql\n\ncat db_world_db.sql\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("h4",{attrs:{id:"★a-2-2-バイナリ形式での出力"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★a-2-2-バイナリ形式での出力"}},[t._v("#")]),t._v(" ★A-2-2 バイナリ形式での出力")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("pg_dump -U suser01 -d db_world --format=c --create --file db_world_db.custom\n\nls -l\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("◎出力結果")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("total 20\n-rw-r--r-- 1 postgres postgres 9710 Jul 10 12:00 db_world_db.custom\n-rw-r--r-- 1 postgres postgres 7561 Jul 10 11:59 db_world_db.sql\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("br"),t._v(" "),s("h2",{attrs:{id:"b-リストア"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#b-リストア"}},[t._v("#")]),t._v(" B.リストア")]),t._v(" "),s("h3",{attrs:{id:"★b-1-データベース削除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★b-1-データベース削除"}},[t._v("#")]),t._v(" ★B-1. データベース削除")]),t._v(" "),s("p",[t._v("データベースが破損したという仮定で、データベースを削除します。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("psql -h localhost -p 5432 -d postgres -U postgres\n\n\\l\ndrop database db_world;\n\\l\n\n\\q\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("br"),t._v(" "),s("h3",{attrs:{id:"★b-2-データベースをリストア"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#★b-2-データベースをリストア"}},[t._v("#")]),t._v(" ★B-2. データベースをリストア")]),t._v(" "),s("p",[t._v("データベースが削除されているため、「db_world」データベースを作成し、"),s("br"),t._v("\n 「db_world_db.custom」を使ってリストアします。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("createdb --template=template0 --encoding='UTF8' --lc-collate='en_US.utf8' --lc-ctype='en_US.utf8' db_world\n\npg_restore -v -c -d db_world /tmp/db_world_db.custom\n\npsql -h localhost -p 5432 -d postgres -U postgres\n\\l\n\\q\n\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br")])]),s("p",[t._v("この操作にてバックアップ取得時の状態へ復旧します。")]),t._v(" "),s("p",[t._v("※この他にもバックアップ取得時点ではなく、障害発生直前にまでリカバリできる"),s("br"),t._v("\n  バックアップコマンド(pg_basebackup)も存在しますがここでは割愛します。")]),t._v(" "),s("br"),t._v(" "),s("hr"),t._v(" "),s("h1",{attrs:{id:"postgresql環境の停止について"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#postgresql環境の停止について"}},[t._v("#")]),t._v(" PostgreSQL環境の停止について")]),t._v(" "),s("p",[t._v("Docker runコマンド実行の際に -d optionをつけている(back ground実行)ため、"),s("br"),t._v("\n★0-3 コンテナ接続"),s("br"),t._v("\nで 開いていた bash で exit してもPostgreSQL(コンテナ)環境は終了しません。")]),t._v(" "),s("p",[t._v("演習が終わりましたらstopコマンドにて停止させてください。"),s("br"),t._v("\npsコマンドにてstatus列 が Exited になっていれば停止となります。"),s("br"),t._v("\n※再度利用する際には docker start some-postgres にて起動可能させます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker stop some-postgres\n\ndocker ps -a\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("以上")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/12.bbadf2b5.js b/assets/js/12.673492fe.js similarity index 99% rename from assets/js/12.bbadf2b5.js rename to assets/js/12.673492fe.js index a474e464..36ed3e64 100644 --- a/assets/js/12.bbadf2b5.js +++ b/assets/js/12.673492fe.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{364:function(s,t,a){s.exports=a.p+"assets/img/git_choosing_editor.65e3a5a8.jpg"},365:function(s,t,a){s.exports=a.p+"assets/img/git_bash_win.e14b57ed.png"},366:function(s,t,a){s.exports=a.p+"assets/img/git_stage.drawio.0ed2f694.svg"},367:function(s,t,a){s.exports=a.p+"assets/img/git_first_commit.drawio.c10d455e.svg"},368:function(s,t,a){s.exports=a.p+"assets/img/git_second_commit.drawio.fc14a864.svg"},369:function(s,t,a){s.exports=a.p+"assets/img/git_branch.drawio.b856c449.svg"},370:function(s,t,a){s.exports=a.p+"assets/img/git_checkout_branch.drawio.39309ca7.svg"},371:function(s,t,a){s.exports=a.p+"assets/img/git_fix_branch_commit.drawio.1c6afc6b.svg"},372:function(s,t,a){s.exports=a.p+"assets/img/git_return_master_branch.drawio.ec0170af.svg"},373:function(s,t,a){s.exports=a.p+"assets/img/git_return_master_branch_commit.drawio.bf34ae5a.svg"},374:function(s,t,a){s.exports=a.p+"assets/img/git_merge.drawio.fc35367e.svg"},522:function(s,t,a){"use strict";a.r(t);var e=a(10),r=Object(e.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("header-table"),s._v(" "),t("h1",{attrs:{id:"page-frontmatter-title"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#page-frontmatter-title"}},[s._v("#")]),s._v(" "+s._s(s.$page.frontmatter.title))]),s._v(" "),t("h2",{attrs:{id:"_0-まえがきと下準備"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-まえがきと下準備"}},[s._v("#")]),s._v(" 0. まえがきと下準備")]),s._v(" "),t("h3",{attrs:{id:"_0-1-この講義の目的"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-この講義の目的"}},[s._v("#")]),s._v(" 0.1. この講義の目的")]),s._v(" "),t("p",[s._v("バージョン管理システムとしてGitを利用し、"),t("strong",[s._v("変更")]),s._v("を管理することの大切さを学び、\nGitとGitHubを使った基本的なソフトウェア開発サイクルを回せるようになることがこの講義の目的です。")]),s._v(" "),t("h3",{attrs:{id:"_0-2-この講義のゴール"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-この講義のゴール"}},[s._v("#")]),s._v(" 0.2. この講義のゴール")]),s._v(" "),t("p",[s._v("手元のPCでGitとGitHubが利用できる状態になっていて、"),t("a",{attrs:{href:"https://gist.github.com/Gab-km/3705015",target:"_blank",rel:"noopener noreferrer"}},[s._v("GitHub Flow"),t("OutboundLink")],1),s._v("を利用した開発ができるようになる。")]),s._v(" "),t("h3",{attrs:{id:"_0-3-想定する受講者"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-想定する受講者"}},[s._v("#")]),s._v(" 0.3. 想定する受講者")]),s._v(" "),t("p",[s._v("これからプログラムを書く、またはテキストファイルによる設定ファイル、マニュアル、仕様書などを記述する可能性のある技術者を対象としています。\n主に新卒の技術職採用者を想定しています。中級者向けの応用的な内容は扱いません。")]),s._v(" "),t("p",[s._v("講義にあたって事前に以下の要件を満たすようにしてください。")]),s._v(" "),t("ul",[t("li",[s._v("ITパスポート試験レベルの技術を理解している。")]),s._v(" "),t("li",[s._v("基礎的なコマンドラインの操作ができる。\n"),t("ul",[t("li",[s._v("ls, cd, mkdirを使ってディレクトリの移動、ファイルの操作が行える。")])])])]),s._v(" "),t("p",[s._v("新卒研修の内容を踏まえたものになっています。\nプログラミング言語の知識は必要ありません。\n自分がこの講義を受講したらよいかわからない、受講できるレベルにあるかわからない場合は担当のメンターに相談してください。")]),s._v(" "),t("h3",{attrs:{id:"_0-4-この講義で取り扱わないこと"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-4-この講義で取り扱わないこと"}},[s._v("#")]),s._v(" 0.4. この講義で取り扱わないこと")]),s._v(" "),t("ul",[t("li",[s._v("RCS(Revision Control System)、Subversionなどのバージョン管理システム")])]),s._v(" "),t("h3",{attrs:{id:"_0-5-この資料のお約束"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-5-この資料のお約束"}},[s._v("#")]),s._v(" 0.5. この資料のお約束")]),s._v(" "),t("p",[s._v("💻 は自分で操作する箇所を示しています。")]),s._v(" "),t("p",[s._v("<ほげほげ> で囲まれている部分は自分の設定値で置き換えてください。たとえば")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git clone <リモートリポジトリのアドレス>\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("と記載されている箇所は")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git clone git@github.com:iij/bootcamp.git\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("というように置き換えてください。")]),s._v(" "),t("h2",{attrs:{id:"_1-gitをインストール"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-gitをインストール"}},[s._v("#")]),s._v(" 1. Gitをインストール")]),s._v(" "),t("p",[s._v("この講義では実際にGitコマンドを操作しながら覚えてもらいます。\n事前に自分のPCにGitをインストールして使えるようにしておきましょう。")]),s._v(" "),t("h3",{attrs:{id:"windows"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#windows"}},[s._v("#")]),s._v(" Windows")]),s._v(" "),t("p",[s._v("先にテキストエディタをインストールしておきましょう。\nメモ帳ではデフォルトの文字コードがUTF-8になっていないことがあります。\nこの講義では"),t("a",{attrs:{href:"https://azure.microsoft.com/ja-jp/products/visual-studio-code/",target:"_blank",rel:"noopener noreferrer"}},[s._v("VSCode"),t("OutboundLink")],1),s._v("を推奨します。\n"),t("a",{attrs:{href:"https://atom.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Atom"),t("OutboundLink")],1),s._v("や"),t("a",{attrs:{href:"https://www.sublimetext.com/3",target:"_blank",rel:"noopener noreferrer"}},[s._v("Sublime Text"),t("OutboundLink")],1),s._v("、"),t("a",{attrs:{href:"https://notepad-plus-plus.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Notepad++"),t("OutboundLink")],1),s._v("を使ってもかまいません。Vimに慣れている人はVimを使ってもよいです。\nメモ帳、サクラエディタは非推奨です。")]),s._v(" "),t("p",[t("a",{attrs:{href:"https://git-scm.com/download/win",target:"_blank",rel:"noopener noreferrer"}},[s._v("Downloading Git"),t("OutboundLink")],1),s._v("から「64-bit Git for Windows Setup」を選んでインストールしてください。")]),s._v(" "),t("p",[s._v("インストール途中で以下のようにGitで利用するテキストエディタに何を使うのかを聞かれます。\nVSCodeをインストールした人は「Use Visual Studio Code as Git's default editor」を選択してください。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(364),alt:"Choosing default editor"}})]),s._v(" "),t("p",[s._v("他のオプションはすべてデフォルトにしてください。\nインストールすると「Git Bash」が起動できるようになっています。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(365),alt:"Git Bashコマンド"}})]),s._v(" "),t("p",[s._v("このハンズオンではGit Bashコマンドを使って進めてください。")]),s._v(" "),t("h3",{attrs:{id:"macos"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#macos"}},[s._v("#")]),s._v(" macOS")]),s._v(" "),t("p",[s._v("macOSでは標準でGitが利用できます。\nXcode(Command Line Tool)が必要で、入っていない場合は時間がかかりますので事前に入れておきましょう。\n最新版のGitが欲しい場合はHomebrewでインストールすることもできます。")]),s._v(" "),t("div",{staticClass:"language-zsh line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("brew install git\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("h3",{attrs:{id:"linux"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#linux"}},[s._v("#")]),s._v(" Linux")]),s._v(" "),t("p",[s._v("ディストリビューションごとのパッケージは "),t("a",{attrs:{href:"https://git-scm.com/download/linux",target:"_blank",rel:"noopener noreferrer"}},[s._v("Download for Linux and Unix\n"),t("OutboundLink")],1),s._v(" に記載されています。")]),s._v(" "),t("h4",{attrs:{id:"インストールの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#インストールの確認"}},[s._v("#")]),s._v(" インストールの確認")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("チェックポイント1 🏁")]),s._v(" "),t("p",[s._v("💻 Gitが正しくインストールされているか確認しましょう。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" --version\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" version "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("2.21")]),s._v(".0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])])]),s._v(" "),t("p",[s._v("Gitのバージョンは2.20以上を使いましょう。古い場合はアップデートしてください。")]),s._v(" "),t("h2",{attrs:{id:"_2-バージョン管理システムとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-バージョン管理システムとは"}},[s._v("#")]),s._v(" 2. バージョン管理システムとは")]),s._v(" "),t("p",[s._v("バージョン管理システム(Version Control System, VCS)とは、\nファイルの「変更」を記録し、"),t("strong",[s._v("誰が")]),s._v("、"),t("strong",[s._v("いつ")]),s._v("、"),t("strong",[s._v("どんな変更を")]),s._v("行ったかを参照できるようにするソフトウェアのことです。\nVCSにはたくさんの種類がありましたが戦国時代を経て、現在ではGitがデファクトスタンダードと言ってもよい状況となっています。")]),s._v(" "),t("h3",{attrs:{id:"_2-1-たくさんのバージョン管理システム"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-たくさんのバージョン管理システム"}},[s._v("#")]),s._v(" 2.1. たくさんのバージョン管理システム")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Git"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://www.mercurial-scm.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Mercurial"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://subversion.apache.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Apache Subversion"),t("OutboundLink")],1)]),s._v(" "),t("li",[s._v("Visual SourceSafe")]),s._v(" "),t("li",[t("a",{attrs:{href:"http://www.bitkeeper.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("BitKeeper"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"http://www.gnu.org/software/rcs/rcs.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("RCS"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("ではなぜVCSを使うとどんなよいことがあるのでしょうか?")]),s._v(" "),t("p",[s._v("まず、最新の状態が一目瞭然です。もう"),t("code",[s._v("最新_コピー(2)_修正版")]),s._v("のようなファイル名を付ける必要はありません。\nいつでも任意の時点の内容にファイルを戻すことができますので安心してファイルを上書きできます。")]),s._v(" "),t("p",[s._v("また問題が発生した場合にいつから発生していたのかを調べたり、昔のファイルに戻して復旧させたり、\nコードを書いた人を調べて直接質問しに行ったりできます。")]),s._v(" "),t("h2",{attrs:{id:"_3-gitの初期設定"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-gitの初期設定"}},[s._v("#")]),s._v(" 3. Gitの初期設定")]),s._v(" "),t("p",[s._v("まずは自分の情報を登録しましょう。")]),s._v(" "),t("p",[s._v("自分の名前とメールアドレスを設定します。\n"),t("code",[s._v("--global")]),s._v("オプションをつけているので、あらゆるリポジトリでこの設定が有効になります。")]),s._v(" "),t("p",[s._v("💻 自分のアカウント情報を設定する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" $ git config --global user.name '<自分の名前>'\n $ git config --global user.email '<自分のメールアドレス>'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("講師が設定する場合は以下のようになります。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" $ git config --global user.name 'Kazuki Hamasaki'\n $ git config --global user.email 'kazuki-h@iij.ad.jp'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("💻 登録した情報を確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git config -l\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("今後コードの変更を行うとその変更の作者を示す情報として、この情報が使用されます。")]),s._v(" "),t("h2",{attrs:{id:"_4-リポジトリを作成する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-リポジトリを作成する"}},[s._v("#")]),s._v(" 4. リポジトリを作成する")]),s._v(" "),t("p",[s._v("ファイルやディレクトリを記録するための場所のことを "),t("strong",[s._v("リポジトリ(Repository)")]),s._v(" と呼びます。\n1つのソフトウェアで1つのリポジトリとすることが多いです。\nEclipseのProjectや、Visual StudioのSolutionの単位と同じと考えてもらうのがよいです。")]),s._v(" "),t("p",[s._v("なにはともあれ、リポジトリがないと始まりません。\n以下の手順でリポジトリを作成してください。")]),s._v(" "),t("p",[s._v("💻 好きな場所にディレクトリを作成し、移動する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ mkdir git_handson\n$ cd git_handson\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("💻 このディレクトリをGitリポジトリとして初期化する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git init\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("これであなたのいるディレクトリはGitリポジトリとなりました。")]),s._v(" "),t("h2",{attrs:{id:"_5-gitの基本-変更の記録"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-gitの基本-変更の記録"}},[s._v("#")]),s._v(" 5. Gitの基本 変更の記録")]),s._v(" "),t("p",[t("img",{attrs:{src:a(366),alt:"gitで管理されるファイルの状態"}})]),s._v(" "),t("p",[s._v("リポジトリの中にGitで変更を管理しないファイルを置いておくこともできます。\nGitで変更を管理することを"),t("code",[s._v("追跡(track)")]),s._v("と呼びます。\n追跡されていないファイルは"),t("code",[s._v("Untracked")]),s._v("です。")]),s._v(" "),t("p",[s._v("追跡されているファイルは"),t("code",[s._v("Unmodified")]),s._v("、"),t("code",[s._v("Modified")]),s._v("、"),t("code",[s._v("Staged")]),s._v("の3つの状態で管理します。")]),s._v(" "),t("ul",[t("li",[s._v("Unmodified\n"),t("ul",[t("li",[s._v("変更されていないファイル")])])]),s._v(" "),t("li",[s._v("Modified\n"),t("ul",[t("li",[s._v("変更されたファイル")])])]),s._v(" "),t("li",[s._v("Staged\n"),t("ul",[t("li",[s._v("ステージされているファイル")])])])]),s._v(" "),t("p",[s._v("変更したファイルはステージングエリアに乗せます。\nステージングエリアに乗っているファイルがまとめてひとつの変更として記録されます。\nファイルの変更を記録することを "),t("strong",[s._v("コミット(Commit)")]),s._v(" と呼びます。")]),s._v(" "),t("h3",{attrs:{id:"_5-1-コミットする"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-コミットする"}},[s._v("#")]),s._v(" 5.1. コミットする")]),s._v(" "),t("p",[s._v("ファイルを作成して、さっそくコミットしましょう。")]),s._v(" "),t("p",[s._v("💻 以下の内容のファイルを作成する。(メモ帳以外のお好きなエディタでどうぞ!)")]),s._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[s._v("WARNING")]),s._v(" "),t("p",[s._v("テキストファイルの文字コードはUTF-8で作成しましょう。このあとの操作で文字化けすることがあります。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("※typo していますが、そのまま記述してください。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\nこんばんは じっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("Gitがファイルをどのように扱っているか確認してみましょう。")]),s._v(" "),t("p",[s._v("💻 ファイルの状態を確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git status\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("以下のように表示されます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('Untracked files:\n (use "git add ..." to include in what will be committed)\n\n\thello.txt\n\nnothing added to commit but untracked files present (use "git add" to track)\n')])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br")])]),t("p",[s._v("リポジトリの中にファイルを置いただけで追跡されるわけではありません。\nそのためファイルを新しく作った場合には"),t("code",[s._v("Untracked")]),s._v("に表示されます。")]),s._v(" "),t("p",[t("code",[s._v("hello.txt")]),s._v("への変更を記録するためにはまずステージングエリアに登録する必要があります。")]),s._v(" "),t("p",[s._v("💻 コミットしたいファイルをステージングエリアへ登録する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ファイルが"),t("code",[s._v("Staged")]),s._v("として登録されていることを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git status\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ステージングエリアのファイルをコミットする。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("コミット時にはメッセージを記入でき、これを"),t("strong",[s._v("コミットメッセージ")]),s._v("と呼びます。\nあとから見たときにどのような変更を入れたかわかりやすくするためのものです。")]),s._v(" "),t("ul",[t("li",[s._v("テキストエディタが起動するので、コミットメッセージを記入します。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" 1 はじめてのgit\n 2\n 3 # Please enter the commit message for your changes. Lines starting\n 4 # with '#' will be ignored, and an empty message aborts the commit.\n 5 #\n 6 # Date: Wed Jun 26 22:08:30 2019 +0900\n 7 #\n 8 # On branch master\n 9 #\n 10 # Initial commit\n 11 #\n 12 # Changes to be committed:\n 13 # new file: hello.txt\n 14 #\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br")])]),t("p",[s._v("VSCodeで編集した場合はファイルを保存して閉じるとコミットは完了です。")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),t("p",[s._v("nanoが起動して困りましたか?\n好きなエディタを使いたい場合は以下のように設定します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git config --global core.editor 'vim -c \"set fenc=utf-8\"'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("atomを使いたい人は"),t("code",[s._v("--wait")]),s._v("オプションが必要です。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('git config --global core.editor "atom --wait"\n')])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])])]),s._v(" "),t("p",[t("img",{attrs:{src:a(367),alt:"Gitの最初のコミット"}})]),s._v(" "),t("p",[s._v("まずは開発の歴史に小さな一歩が刻まれました。(小さな一歩のイメージ図)")]),s._v(" "),t("h4",{attrs:{id:"_5-1-1-コミットメッセージには理由を書こう"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-1-コミットメッセージには理由を書こう"}},[s._v("#")]),s._v(" 5.1.1. コミットメッセージには理由を書こう")]),s._v(" "),t("p",[s._v("コミットメッセージには"),t("strong",[s._v("なぜその修正を入れたのか")]),s._v("理由を書くようにしましょう。")]),s._v(" "),t("p",[s._v("どんな修正を入れたかは履歴を見れば確認できます。\nなぜその修正を入れる必要があったかは往々にしてコードには現れません。\nそれを残しておくための場所がコミットメッセージです。")]),s._v(" "),t("h3",{attrs:{id:"_5-2-コミットの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-2-コミットの確認"}},[s._v("#")]),s._v(" 5.2. コミットの確認")]),s._v(" "),t("p",[s._v("💻 歴史が刻まれていることを確認します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n\ncommit b8490bfc83a2c91bac6772b2f9e533ccf2455baf (HEAD -> master)\nAuthor: Kazuki Hamasaki \nDate: Wed Jun 26 22:08:30 2019 +0900\n\n はじめてのgit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br")])]),t("p",[t("code",[s._v("commit")]),s._v("はコミットごとに発行される一意のIDでコミットハッシュ値と呼ばれています。\n"),t("code",[s._v("Author")]),s._v("はコミットを作成した人です。「2. Gitの初期設定」で設定した値が使われているはずです。\n"),t("code",[s._v("Data")]),s._v("はコミット日時ですね。\nその下にはコミットコメントが表示されています。")]),s._v(" "),t("p",[s._v("しかしどんな変更を入れたか表示されていませんね。")]),s._v(" "),t("p",[s._v("💻 前回のコミットの内容を表示してみる")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("code",[s._v("git show")]),s._v("では変更に関する差分のみが表示されます。\nここの差分はユニファイド形式になっています。\n"),t("code",[s._v("+")]),s._v("が追加された行で、"),t("code",[s._v("-")]),s._v("が削除された行です。\nファイルがまるごと追加されたため、すべての行が追加されたという表示になっています。")]),s._v(" "),t("p",[s._v("よく見たら"),t("a",{attrs:{href:"http://e-words.jp/w/%E3%82%BF%E3%82%A4%E3%83%9D.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("typo"),t("OutboundLink")],1),s._v("してますよね。直してみましょう。")]),s._v(" "),t("h3",{attrs:{id:"_5-3-さらにコミットを積み重ねる"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-3-さらにコミットを積み重ねる"}},[s._v("#")]),s._v(" 5.3. さらにコミットを積み重ねる")]),s._v(" "),t("p",[s._v("💻 typoを直しましょう。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\n"),t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは じっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは ぎっと\n")])])])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("上はファイルをどう編集するかという差分になっています。+や-をコピペしないようにしましょう。")]),s._v(" "),t("p",[s._v("💻 コミットする前に、前コミットとの変更差分をみてみます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git diff\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("タイポだけを直せていますか?")]),s._v(" "),t("p",[s._v("💻 問題なければコミットします。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n$ git status\n$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("コミットコメントは好きに考えてみてください。")]),s._v(" "),t("p",[s._v("💻 コミットの確認")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("コミットの履歴と差分をまとめて見るには"),t("code",[s._v("git log")]),s._v("の"),t("code",[s._v("-p")]),s._v("オプションが利用できます。")]),s._v(" "),t("p",[s._v("💻 コミットの履歴と差分をまとめて確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git log -p\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(368),alt:"Gitで2回目のコミット"}})]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("コミットとコミットとの間の矢印は逆じゃないの?")]),s._v(" "),t("p",[s._v("Gitのコミットオブジェクトは直前のコミットへのポインタを持っています。\n詳しく知りたい人は "),t("a",{attrs:{href:"https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88#r_git_commit_objects",target:"_blank",rel:"noopener noreferrer"}},[s._v("Gitの内側 - Gitオブジェクト コミットオブジェクト"),t("OutboundLink")],1),s._v("をご覧ください。")])]),s._v(" "),t("h2",{attrs:{id:"_6-ブランチ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-ブランチ"}},[s._v("#")]),s._v(" 6. ブランチ")]),s._v(" "),t("h3",{attrs:{id:"_6-1-実はあなたは今、-master-というブランチにいます"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-1-実はあなたは今、-master-というブランチにいます"}},[s._v("#")]),s._v(' 6.1. 実はあなたは今、"master"というブランチにいます')]),s._v(" "),t("p",[t("code",[s._v("ブランチ(Branch)")]),s._v("とは、履歴の流れを分岐させて記録するしくみです。\nGitリポジトリを作成すると、自動的に"),t("code",[s._v("master")]),s._v("ブランチが1つ作成されています。")]),s._v(" "),t("p",[s._v("💻 現在のブランチを確認してみましょう")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('"*" は現在のブランチを指しています。')]),s._v(" "),t("p",[s._v("ブランチの切り方としては、作業内容単位で切っていくのが一般的です。\n何か作業をするときはとりあえずブランチを切ってそこで作業を行い、\n完了しだい"),t("code",[s._v("master")]),s._v("ブランチに反映させます。")]),s._v(" "),t("p",[t("code",[s._v("master")]),s._v("ブランチをそのままメインブランチとして扱うことが多いです。\n今回もその慣習に従います。")]),s._v(" "),t("h3",{attrs:{id:"_6-2-新たな-branch-を作る"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-新たな-branch-を作る"}},[s._v("#")]),s._v(" 6.2. 新たな Branch を作る")]),s._v(" "),t("p",[s._v('今度は "ぎっと" を "Git" に直したい。\nせっかくですので別のブランチで作業してみましょう。')]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("fix")]),s._v("というブランチを作成する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ブランチを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(369),alt:"fixブランチを作成した"}})]),s._v(" "),t("p",[t("code",[s._v("fix")]),s._v("ブランチを作成したものの、\nあなたはまだ"),t("code",[s._v("master")]),s._v("ブランチにいるままです。")]),s._v(" "),t("h3",{attrs:{id:"_6-3-ブランチを移動する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-ブランチを移動する"}},[s._v("#")]),s._v(" 6.3. ブランチを移動する")]),s._v(" "),t("p",[s._v('💻 "fix" Branch へ移動するために Checkout する。')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 現在のブランチを確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('" * " が "fix" を指すようになりましたね?')]),s._v(" "),t("p",[t("img",{attrs:{src:a(370),alt:"fixブランチを作成した"}})]),s._v(" "),t("p",[s._v("💻 コミットを確認してみる")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("ブランチを作成した時点での"),t("code",[s._v("master")]),s._v("ブランチのコミットが引き継がれているはずです。")]),s._v(" "),t("h3",{attrs:{id:"_6-4-fix-ブランチで-commit-する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-4-fix-ブランチで-commit-する"}},[s._v("#")]),s._v(' 6.4. "fix"ブランチで Commit する')]),s._v(" "),t("p",[s._v("💻 ファイルを書き換える")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おはよう ぎっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おはよう Git\n")])]),s._v("こんにちは ぎっと\nこんばんは ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("💻 Commit する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n$ git status\n$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[t("img",{attrs:{src:a(371),alt:"fixブランチでコミットした"}})]),s._v(" "),t("p",[s._v("💻 今いるfixブランチのファイルを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("これにより "),t("code",[s._v("fix")]),s._v("ブランチで Commit を積むことができました。\n"),t("code",[s._v("master")]),s._v("ブランチに戻るとどう見えるでしょう。")]),s._v(" "),t("h3",{attrs:{id:"_6-5-master-ブランチへ戻る"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-5-master-ブランチへ戻る"}},[s._v("#")]),s._v(' 6.5. "master"ブランチへ戻る')]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("master")]),s._v(" へ移動するために Checkout します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout master\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(372),alt:"masterブランチに戻った"}})]),s._v(" "),t("p",[s._v('💻 "master"ブランチの履歴を見る。')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v('先ほどの「6.4. "fix"ブランチで Commit する」で行ったコミットは"fix"ブランチで行ったものですので、masterブランチでは見えません。')]),s._v(" "),t("p",[s._v("複数人で開発する場合には同時にいくつもの変更が行われていることがあります。\n"),t("code",[s._v("fix")]),s._v("ブランチで修正中ですが、並行して"),t("code",[s._v("master")]),s._v("ブランチでも変更を入れてみましょう。")]),s._v(" "),t("p",[s._v("💻 masterブランチで別のコミットをする")]),s._v(" "),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\n"),t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは ぎっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おやすみ ぎっと\n")])])])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[t("img",{attrs:{src:a(373),alt:"masterブランチに戻った"}})]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("master")]),s._v("と"),t("code",[s._v("fix")]),s._v("の2つのブランチを言ったり来たりして、ファイルの状態が変わることを確認しましょう。")]),s._v(" "),t("h3",{attrs:{id:"_6-6-マージする"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-6-マージする"}},[s._v("#")]),s._v(" 6.6. マージする")]),s._v(" "),t("p",[s._v("今いるブランチに他のブランチでの変更を取り込むことをマージ(merge)と呼びます。")]),s._v(" "),t("p",[s._v("修正が完了して問題がないことを完了したのでこの修正を"),t("code",[s._v("master")]),s._v("ブランチに取り込みます。\n"),t("code",[s._v("master")]),s._v('ブランチに "fix"ブランチの変更を取り込みます。')]),s._v(" "),t("p",[t("code",[s._v("master")]),s._v("ブランチの内容は")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("に"),t("code",[s._v("fix")]),s._v("ブランチの内容")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nこんばんは ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("を取り込みます。すると")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("となるはずです。歴史は以下のようになります。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(374),alt:"ブランチをマージする"}})]),s._v(" "),t("p",[s._v("ブランチをマージするには"),t("code",[s._v("git merge")]),s._v("コマンドを使います。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git merge <取り込みたいブランチ名>\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('💻 "master"ブランチへ移動してから"fix"ブランチの変更内容を、メインである"master"ブランチへ取り込みましょう')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout master\n$ git merge fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("マージするときのコミットコメントはデフォルトでOKです。")]),s._v(" "),t("p",[s._v("💻 マージされたファイルがどのように変更されたのか確認してみましょう")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[t("code",[s._v("fix")]),s._v("ブランチで行ったコミットが取り込まれているでしょうか?")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("チェックポイント2 🏁")]),s._v(" "),t("p",[s._v("hello.txtが以下のようになっていれば正解です!")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])])]),s._v(" "),t("p",[s._v("Git の基本操作を一通り流してやってみました。\nGit ハンズオンは以上で終了です。")]),s._v(" "),t("p",[s._v("次は "),t("a",{attrs:{href:"../github"}},[s._v("GitHub ハンズオン")]),s._v(" に進んでください。")]),s._v(" "),t("h2",{attrs:{id:"_7-参考文献"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_7-参考文献"}},[s._v("#")]),s._v(" 7. 参考文献")]),s._v(" "),t("p",[s._v("さらに高度な使い方を知りたい方は"),t("a",{attrs:{href:"https://git-scm.com/book/ja/v2",target:"_blank",rel:"noopener noreferrer"}},[s._v("Pro Git"),t("OutboundLink")],1),s._v("が便利です。日本語版が公開されています。")]),s._v(" "),t("p",[s._v("こんな説明じゃブランチがわからん!という人は "),t("a",{attrs:{href:"https://learngitbranching.js.org/?locale=ja",target:"_blank",rel:"noopener noreferrer"}},[s._v("Learn Git Branching (日本語版)"),t("OutboundLink")],1),s._v(" で練習できます。")]),s._v(" "),t("h3",{attrs:{id:"_7-1-guiクライアント"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_7-1-guiクライアント"}},[s._v("#")]),s._v(" 7.1. GUIクライアント")]),s._v(" "),t("p",[s._v("Gitには、機能が限定されますがGUIクライアントも用意されています。おすすめは以下の3つのクライアントです。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://desktop.github.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("GitHub Desktop (Win, macOS)"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://tortoisegit.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("TortoiseGit (Win)"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://www.sourcetreeapp.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("SourceTree (Win, macOS)"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("また各種統合開発環境にもGitを操作する機能が含まれています。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://code.visualstudio.com/docs/editor/versioncontrol",target:"_blank",rel:"noopener noreferrer"}},[s._v("Using Version Control in VS Code"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://pleiades.io/help/idea/using-git-integration.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("Git - ヘルプ | IntelliJ IDEA"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("これらのクライアントの利用も検討してください。")]),s._v(" "),t("credit-footer")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{364:function(s,t,a){s.exports=a.p+"assets/img/git_choosing_editor.65e3a5a8.jpg"},365:function(s,t,a){s.exports=a.p+"assets/img/git_bash_win.e14b57ed.png"},366:function(s,t,a){s.exports=a.p+"assets/img/git_stage.drawio.0ed2f694.svg"},367:function(s,t,a){s.exports=a.p+"assets/img/git_first_commit.drawio.c10d455e.svg"},368:function(s,t,a){s.exports=a.p+"assets/img/git_second_commit.drawio.fc14a864.svg"},369:function(s,t,a){s.exports=a.p+"assets/img/git_branch.drawio.b856c449.svg"},370:function(s,t,a){s.exports=a.p+"assets/img/git_checkout_branch.drawio.39309ca7.svg"},371:function(s,t,a){s.exports=a.p+"assets/img/git_fix_branch_commit.drawio.1c6afc6b.svg"},372:function(s,t,a){s.exports=a.p+"assets/img/git_return_master_branch.drawio.ec0170af.svg"},373:function(s,t,a){s.exports=a.p+"assets/img/git_return_master_branch_commit.drawio.bf34ae5a.svg"},374:function(s,t,a){s.exports=a.p+"assets/img/git_merge.drawio.fc35367e.svg"},521:function(s,t,a){"use strict";a.r(t);var e=a(10),r=Object(e.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("header-table"),s._v(" "),t("h1",{attrs:{id:"page-frontmatter-title"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#page-frontmatter-title"}},[s._v("#")]),s._v(" "+s._s(s.$page.frontmatter.title))]),s._v(" "),t("h2",{attrs:{id:"_0-まえがきと下準備"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-まえがきと下準備"}},[s._v("#")]),s._v(" 0. まえがきと下準備")]),s._v(" "),t("h3",{attrs:{id:"_0-1-この講義の目的"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-この講義の目的"}},[s._v("#")]),s._v(" 0.1. この講義の目的")]),s._v(" "),t("p",[s._v("バージョン管理システムとしてGitを利用し、"),t("strong",[s._v("変更")]),s._v("を管理することの大切さを学び、\nGitとGitHubを使った基本的なソフトウェア開発サイクルを回せるようになることがこの講義の目的です。")]),s._v(" "),t("h3",{attrs:{id:"_0-2-この講義のゴール"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-この講義のゴール"}},[s._v("#")]),s._v(" 0.2. この講義のゴール")]),s._v(" "),t("p",[s._v("手元のPCでGitとGitHubが利用できる状態になっていて、"),t("a",{attrs:{href:"https://gist.github.com/Gab-km/3705015",target:"_blank",rel:"noopener noreferrer"}},[s._v("GitHub Flow"),t("OutboundLink")],1),s._v("を利用した開発ができるようになる。")]),s._v(" "),t("h3",{attrs:{id:"_0-3-想定する受講者"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-想定する受講者"}},[s._v("#")]),s._v(" 0.3. 想定する受講者")]),s._v(" "),t("p",[s._v("これからプログラムを書く、またはテキストファイルによる設定ファイル、マニュアル、仕様書などを記述する可能性のある技術者を対象としています。\n主に新卒の技術職採用者を想定しています。中級者向けの応用的な内容は扱いません。")]),s._v(" "),t("p",[s._v("講義にあたって事前に以下の要件を満たすようにしてください。")]),s._v(" "),t("ul",[t("li",[s._v("ITパスポート試験レベルの技術を理解している。")]),s._v(" "),t("li",[s._v("基礎的なコマンドラインの操作ができる。\n"),t("ul",[t("li",[s._v("ls, cd, mkdirを使ってディレクトリの移動、ファイルの操作が行える。")])])])]),s._v(" "),t("p",[s._v("新卒研修の内容を踏まえたものになっています。\nプログラミング言語の知識は必要ありません。\n自分がこの講義を受講したらよいかわからない、受講できるレベルにあるかわからない場合は担当のメンターに相談してください。")]),s._v(" "),t("h3",{attrs:{id:"_0-4-この講義で取り扱わないこと"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-4-この講義で取り扱わないこと"}},[s._v("#")]),s._v(" 0.4. この講義で取り扱わないこと")]),s._v(" "),t("ul",[t("li",[s._v("RCS(Revision Control System)、Subversionなどのバージョン管理システム")])]),s._v(" "),t("h3",{attrs:{id:"_0-5-この資料のお約束"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-5-この資料のお約束"}},[s._v("#")]),s._v(" 0.5. この資料のお約束")]),s._v(" "),t("p",[s._v("💻 は自分で操作する箇所を示しています。")]),s._v(" "),t("p",[s._v("<ほげほげ> で囲まれている部分は自分の設定値で置き換えてください。たとえば")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git clone <リモートリポジトリのアドレス>\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("と記載されている箇所は")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git clone git@github.com:iij/bootcamp.git\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("というように置き換えてください。")]),s._v(" "),t("h2",{attrs:{id:"_1-gitをインストール"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-gitをインストール"}},[s._v("#")]),s._v(" 1. Gitをインストール")]),s._v(" "),t("p",[s._v("この講義では実際にGitコマンドを操作しながら覚えてもらいます。\n事前に自分のPCにGitをインストールして使えるようにしておきましょう。")]),s._v(" "),t("h3",{attrs:{id:"windows"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#windows"}},[s._v("#")]),s._v(" Windows")]),s._v(" "),t("p",[s._v("先にテキストエディタをインストールしておきましょう。\nメモ帳ではデフォルトの文字コードがUTF-8になっていないことがあります。\nこの講義では"),t("a",{attrs:{href:"https://azure.microsoft.com/ja-jp/products/visual-studio-code/",target:"_blank",rel:"noopener noreferrer"}},[s._v("VSCode"),t("OutboundLink")],1),s._v("を推奨します。\n"),t("a",{attrs:{href:"https://atom.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Atom"),t("OutboundLink")],1),s._v("や"),t("a",{attrs:{href:"https://www.sublimetext.com/3",target:"_blank",rel:"noopener noreferrer"}},[s._v("Sublime Text"),t("OutboundLink")],1),s._v("、"),t("a",{attrs:{href:"https://notepad-plus-plus.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Notepad++"),t("OutboundLink")],1),s._v("を使ってもかまいません。Vimに慣れている人はVimを使ってもよいです。\nメモ帳、サクラエディタは非推奨です。")]),s._v(" "),t("p",[t("a",{attrs:{href:"https://git-scm.com/download/win",target:"_blank",rel:"noopener noreferrer"}},[s._v("Downloading Git"),t("OutboundLink")],1),s._v("から「64-bit Git for Windows Setup」を選んでインストールしてください。")]),s._v(" "),t("p",[s._v("インストール途中で以下のようにGitで利用するテキストエディタに何を使うのかを聞かれます。\nVSCodeをインストールした人は「Use Visual Studio Code as Git's default editor」を選択してください。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(364),alt:"Choosing default editor"}})]),s._v(" "),t("p",[s._v("他のオプションはすべてデフォルトにしてください。\nインストールすると「Git Bash」が起動できるようになっています。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(365),alt:"Git Bashコマンド"}})]),s._v(" "),t("p",[s._v("このハンズオンではGit Bashコマンドを使って進めてください。")]),s._v(" "),t("h3",{attrs:{id:"macos"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#macos"}},[s._v("#")]),s._v(" macOS")]),s._v(" "),t("p",[s._v("macOSでは標準でGitが利用できます。\nXcode(Command Line Tool)が必要で、入っていない場合は時間がかかりますので事前に入れておきましょう。\n最新版のGitが欲しい場合はHomebrewでインストールすることもできます。")]),s._v(" "),t("div",{staticClass:"language-zsh line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("brew install git\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("h3",{attrs:{id:"linux"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#linux"}},[s._v("#")]),s._v(" Linux")]),s._v(" "),t("p",[s._v("ディストリビューションごとのパッケージは "),t("a",{attrs:{href:"https://git-scm.com/download/linux",target:"_blank",rel:"noopener noreferrer"}},[s._v("Download for Linux and Unix\n"),t("OutboundLink")],1),s._v(" に記載されています。")]),s._v(" "),t("h4",{attrs:{id:"インストールの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#インストールの確認"}},[s._v("#")]),s._v(" インストールの確認")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("チェックポイント1 🏁")]),s._v(" "),t("p",[s._v("💻 Gitが正しくインストールされているか確認しましょう。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" --version\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("git")]),s._v(" version "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("2.21")]),s._v(".0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])])]),s._v(" "),t("p",[s._v("Gitのバージョンは2.20以上を使いましょう。古い場合はアップデートしてください。")]),s._v(" "),t("h2",{attrs:{id:"_2-バージョン管理システムとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-バージョン管理システムとは"}},[s._v("#")]),s._v(" 2. バージョン管理システムとは")]),s._v(" "),t("p",[s._v("バージョン管理システム(Version Control System, VCS)とは、\nファイルの「変更」を記録し、"),t("strong",[s._v("誰が")]),s._v("、"),t("strong",[s._v("いつ")]),s._v("、"),t("strong",[s._v("どんな変更を")]),s._v("行ったかを参照できるようにするソフトウェアのことです。\nVCSにはたくさんの種類がありましたが戦国時代を経て、現在ではGitがデファクトスタンダードと言ってもよい状況となっています。")]),s._v(" "),t("h3",{attrs:{id:"_2-1-たくさんのバージョン管理システム"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-たくさんのバージョン管理システム"}},[s._v("#")]),s._v(" 2.1. たくさんのバージョン管理システム")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://git-scm.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Git"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://www.mercurial-scm.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Mercurial"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://subversion.apache.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Apache Subversion"),t("OutboundLink")],1)]),s._v(" "),t("li",[s._v("Visual SourceSafe")]),s._v(" "),t("li",[t("a",{attrs:{href:"http://www.bitkeeper.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("BitKeeper"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"http://www.gnu.org/software/rcs/rcs.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("RCS"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("ではなぜVCSを使うとどんなよいことがあるのでしょうか?")]),s._v(" "),t("p",[s._v("まず、最新の状態が一目瞭然です。もう"),t("code",[s._v("最新_コピー(2)_修正版")]),s._v("のようなファイル名を付ける必要はありません。\nいつでも任意の時点の内容にファイルを戻すことができますので安心してファイルを上書きできます。")]),s._v(" "),t("p",[s._v("また問題が発生した場合にいつから発生していたのかを調べたり、昔のファイルに戻して復旧させたり、\nコードを書いた人を調べて直接質問しに行ったりできます。")]),s._v(" "),t("h2",{attrs:{id:"_3-gitの初期設定"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-gitの初期設定"}},[s._v("#")]),s._v(" 3. Gitの初期設定")]),s._v(" "),t("p",[s._v("まずは自分の情報を登録しましょう。")]),s._v(" "),t("p",[s._v("自分の名前とメールアドレスを設定します。\n"),t("code",[s._v("--global")]),s._v("オプションをつけているので、あらゆるリポジトリでこの設定が有効になります。")]),s._v(" "),t("p",[s._v("💻 自分のアカウント情報を設定する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" $ git config --global user.name '<自分の名前>'\n $ git config --global user.email '<自分のメールアドレス>'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("講師が設定する場合は以下のようになります。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" $ git config --global user.name 'Kazuki Hamasaki'\n $ git config --global user.email 'kazuki-h@iij.ad.jp'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("💻 登録した情報を確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git config -l\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("今後コードの変更を行うとその変更の作者を示す情報として、この情報が使用されます。")]),s._v(" "),t("h2",{attrs:{id:"_4-リポジトリを作成する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-リポジトリを作成する"}},[s._v("#")]),s._v(" 4. リポジトリを作成する")]),s._v(" "),t("p",[s._v("ファイルやディレクトリを記録するための場所のことを "),t("strong",[s._v("リポジトリ(Repository)")]),s._v(" と呼びます。\n1つのソフトウェアで1つのリポジトリとすることが多いです。\nEclipseのProjectや、Visual StudioのSolutionの単位と同じと考えてもらうのがよいです。")]),s._v(" "),t("p",[s._v("なにはともあれ、リポジトリがないと始まりません。\n以下の手順でリポジトリを作成してください。")]),s._v(" "),t("p",[s._v("💻 好きな場所にディレクトリを作成し、移動する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ mkdir git_handson\n$ cd git_handson\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("💻 このディレクトリをGitリポジトリとして初期化する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git init\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("これであなたのいるディレクトリはGitリポジトリとなりました。")]),s._v(" "),t("h2",{attrs:{id:"_5-gitの基本-変更の記録"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-gitの基本-変更の記録"}},[s._v("#")]),s._v(" 5. Gitの基本 変更の記録")]),s._v(" "),t("p",[t("img",{attrs:{src:a(366),alt:"gitで管理されるファイルの状態"}})]),s._v(" "),t("p",[s._v("リポジトリの中にGitで変更を管理しないファイルを置いておくこともできます。\nGitで変更を管理することを"),t("code",[s._v("追跡(track)")]),s._v("と呼びます。\n追跡されていないファイルは"),t("code",[s._v("Untracked")]),s._v("です。")]),s._v(" "),t("p",[s._v("追跡されているファイルは"),t("code",[s._v("Unmodified")]),s._v("、"),t("code",[s._v("Modified")]),s._v("、"),t("code",[s._v("Staged")]),s._v("の3つの状態で管理します。")]),s._v(" "),t("ul",[t("li",[s._v("Unmodified\n"),t("ul",[t("li",[s._v("変更されていないファイル")])])]),s._v(" "),t("li",[s._v("Modified\n"),t("ul",[t("li",[s._v("変更されたファイル")])])]),s._v(" "),t("li",[s._v("Staged\n"),t("ul",[t("li",[s._v("ステージされているファイル")])])])]),s._v(" "),t("p",[s._v("変更したファイルはステージングエリアに乗せます。\nステージングエリアに乗っているファイルがまとめてひとつの変更として記録されます。\nファイルの変更を記録することを "),t("strong",[s._v("コミット(Commit)")]),s._v(" と呼びます。")]),s._v(" "),t("h3",{attrs:{id:"_5-1-コミットする"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-コミットする"}},[s._v("#")]),s._v(" 5.1. コミットする")]),s._v(" "),t("p",[s._v("ファイルを作成して、さっそくコミットしましょう。")]),s._v(" "),t("p",[s._v("💻 以下の内容のファイルを作成する。(メモ帳以外のお好きなエディタでどうぞ!)")]),s._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[s._v("WARNING")]),s._v(" "),t("p",[s._v("テキストファイルの文字コードはUTF-8で作成しましょう。このあとの操作で文字化けすることがあります。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("※typo していますが、そのまま記述してください。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\nこんばんは じっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("Gitがファイルをどのように扱っているか確認してみましょう。")]),s._v(" "),t("p",[s._v("💻 ファイルの状態を確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git status\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("以下のように表示されます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('Untracked files:\n (use "git add ..." to include in what will be committed)\n\n\thello.txt\n\nnothing added to commit but untracked files present (use "git add" to track)\n')])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br")])]),t("p",[s._v("リポジトリの中にファイルを置いただけで追跡されるわけではありません。\nそのためファイルを新しく作った場合には"),t("code",[s._v("Untracked")]),s._v("に表示されます。")]),s._v(" "),t("p",[t("code",[s._v("hello.txt")]),s._v("への変更を記録するためにはまずステージングエリアに登録する必要があります。")]),s._v(" "),t("p",[s._v("💻 コミットしたいファイルをステージングエリアへ登録する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ファイルが"),t("code",[s._v("Staged")]),s._v("として登録されていることを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git status\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ステージングエリアのファイルをコミットする。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("コミット時にはメッセージを記入でき、これを"),t("strong",[s._v("コミットメッセージ")]),s._v("と呼びます。\nあとから見たときにどのような変更を入れたかわかりやすくするためのものです。")]),s._v(" "),t("ul",[t("li",[s._v("テキストエディタが起動するので、コミットメッセージを記入します。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v(" 1 はじめてのgit\n 2\n 3 # Please enter the commit message for your changes. Lines starting\n 4 # with '#' will be ignored, and an empty message aborts the commit.\n 5 #\n 6 # Date: Wed Jun 26 22:08:30 2019 +0900\n 7 #\n 8 # On branch master\n 9 #\n 10 # Initial commit\n 11 #\n 12 # Changes to be committed:\n 13 # new file: hello.txt\n 14 #\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br")])]),t("p",[s._v("VSCodeで編集した場合はファイルを保存して閉じるとコミットは完了です。")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),t("p",[s._v("nanoが起動して困りましたか?\n好きなエディタを使いたい場合は以下のように設定します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git config --global core.editor 'vim -c \"set fenc=utf-8\"'\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("atomを使いたい人は"),t("code",[s._v("--wait")]),s._v("オプションが必要です。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('git config --global core.editor "atom --wait"\n')])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])])]),s._v(" "),t("p",[t("img",{attrs:{src:a(367),alt:"Gitの最初のコミット"}})]),s._v(" "),t("p",[s._v("まずは開発の歴史に小さな一歩が刻まれました。(小さな一歩のイメージ図)")]),s._v(" "),t("h4",{attrs:{id:"_5-1-1-コミットメッセージには理由を書こう"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-1-コミットメッセージには理由を書こう"}},[s._v("#")]),s._v(" 5.1.1. コミットメッセージには理由を書こう")]),s._v(" "),t("p",[s._v("コミットメッセージには"),t("strong",[s._v("なぜその修正を入れたのか")]),s._v("理由を書くようにしましょう。")]),s._v(" "),t("p",[s._v("どんな修正を入れたかは履歴を見れば確認できます。\nなぜその修正を入れる必要があったかは往々にしてコードには現れません。\nそれを残しておくための場所がコミットメッセージです。")]),s._v(" "),t("h3",{attrs:{id:"_5-2-コミットの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-2-コミットの確認"}},[s._v("#")]),s._v(" 5.2. コミットの確認")]),s._v(" "),t("p",[s._v("💻 歴史が刻まれていることを確認します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n\ncommit b8490bfc83a2c91bac6772b2f9e533ccf2455baf (HEAD -> master)\nAuthor: Kazuki Hamasaki \nDate: Wed Jun 26 22:08:30 2019 +0900\n\n はじめてのgit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br")])]),t("p",[t("code",[s._v("commit")]),s._v("はコミットごとに発行される一意のIDでコミットハッシュ値と呼ばれています。\n"),t("code",[s._v("Author")]),s._v("はコミットを作成した人です。「2. Gitの初期設定」で設定した値が使われているはずです。\n"),t("code",[s._v("Data")]),s._v("はコミット日時ですね。\nその下にはコミットコメントが表示されています。")]),s._v(" "),t("p",[s._v("しかしどんな変更を入れたか表示されていませんね。")]),s._v(" "),t("p",[s._v("💻 前回のコミットの内容を表示してみる")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("code",[s._v("git show")]),s._v("では変更に関する差分のみが表示されます。\nここの差分はユニファイド形式になっています。\n"),t("code",[s._v("+")]),s._v("が追加された行で、"),t("code",[s._v("-")]),s._v("が削除された行です。\nファイルがまるごと追加されたため、すべての行が追加されたという表示になっています。")]),s._v(" "),t("p",[s._v("よく見たら"),t("a",{attrs:{href:"http://e-words.jp/w/%E3%82%BF%E3%82%A4%E3%83%9D.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("typo"),t("OutboundLink")],1),s._v("してますよね。直してみましょう。")]),s._v(" "),t("h3",{attrs:{id:"_5-3-さらにコミットを積み重ねる"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-3-さらにコミットを積み重ねる"}},[s._v("#")]),s._v(" 5.3. さらにコミットを積み重ねる")]),s._v(" "),t("p",[s._v("💻 typoを直しましょう。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\n"),t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは じっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは ぎっと\n")])])])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("上はファイルをどう編集するかという差分になっています。+や-をコピペしないようにしましょう。")]),s._v(" "),t("p",[s._v("💻 コミットする前に、前コミットとの変更差分をみてみます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git diff\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("タイポだけを直せていますか?")]),s._v(" "),t("p",[s._v("💻 問題なければコミットします。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n$ git status\n$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("コミットコメントは好きに考えてみてください。")]),s._v(" "),t("p",[s._v("💻 コミットの確認")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("コミットの履歴と差分をまとめて見るには"),t("code",[s._v("git log")]),s._v("の"),t("code",[s._v("-p")]),s._v("オプションが利用できます。")]),s._v(" "),t("p",[s._v("💻 コミットの履歴と差分をまとめて確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("git log -p\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(368),alt:"Gitで2回目のコミット"}})]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("コミットとコミットとの間の矢印は逆じゃないの?")]),s._v(" "),t("p",[s._v("Gitのコミットオブジェクトは直前のコミットへのポインタを持っています。\n詳しく知りたい人は "),t("a",{attrs:{href:"https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88#r_git_commit_objects",target:"_blank",rel:"noopener noreferrer"}},[s._v("Gitの内側 - Gitオブジェクト コミットオブジェクト"),t("OutboundLink")],1),s._v("をご覧ください。")])]),s._v(" "),t("h2",{attrs:{id:"_6-ブランチ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-ブランチ"}},[s._v("#")]),s._v(" 6. ブランチ")]),s._v(" "),t("h3",{attrs:{id:"_6-1-実はあなたは今、-master-というブランチにいます"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-1-実はあなたは今、-master-というブランチにいます"}},[s._v("#")]),s._v(' 6.1. 実はあなたは今、"master"というブランチにいます')]),s._v(" "),t("p",[t("code",[s._v("ブランチ(Branch)")]),s._v("とは、履歴の流れを分岐させて記録するしくみです。\nGitリポジトリを作成すると、自動的に"),t("code",[s._v("master")]),s._v("ブランチが1つ作成されています。")]),s._v(" "),t("p",[s._v("💻 現在のブランチを確認してみましょう")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('"*" は現在のブランチを指しています。')]),s._v(" "),t("p",[s._v("ブランチの切り方としては、作業内容単位で切っていくのが一般的です。\n何か作業をするときはとりあえずブランチを切ってそこで作業を行い、\n完了しだい"),t("code",[s._v("master")]),s._v("ブランチに反映させます。")]),s._v(" "),t("p",[t("code",[s._v("master")]),s._v("ブランチをそのままメインブランチとして扱うことが多いです。\n今回もその慣習に従います。")]),s._v(" "),t("h3",{attrs:{id:"_6-2-新たな-branch-を作る"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-新たな-branch-を作る"}},[s._v("#")]),s._v(" 6.2. 新たな Branch を作る")]),s._v(" "),t("p",[s._v('今度は "ぎっと" を "Git" に直したい。\nせっかくですので別のブランチで作業してみましょう。')]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("fix")]),s._v("というブランチを作成する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 ブランチを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(369),alt:"fixブランチを作成した"}})]),s._v(" "),t("p",[t("code",[s._v("fix")]),s._v("ブランチを作成したものの、\nあなたはまだ"),t("code",[s._v("master")]),s._v("ブランチにいるままです。")]),s._v(" "),t("h3",{attrs:{id:"_6-3-ブランチを移動する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-ブランチを移動する"}},[s._v("#")]),s._v(" 6.3. ブランチを移動する")]),s._v(" "),t("p",[s._v('💻 "fix" Branch へ移動するために Checkout する。')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("💻 現在のブランチを確認する")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git branch\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('" * " が "fix" を指すようになりましたね?')]),s._v(" "),t("p",[t("img",{attrs:{src:a(370),alt:"fixブランチを作成した"}})]),s._v(" "),t("p",[s._v("💻 コミットを確認してみる")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("ブランチを作成した時点での"),t("code",[s._v("master")]),s._v("ブランチのコミットが引き継がれているはずです。")]),s._v(" "),t("h3",{attrs:{id:"_6-4-fix-ブランチで-commit-する"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-4-fix-ブランチで-commit-する"}},[s._v("#")]),s._v(' 6.4. "fix"ブランチで Commit する')]),s._v(" "),t("p",[s._v("💻 ファイルを書き換える")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ code hello.txt\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おはよう ぎっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おはよう Git\n")])]),s._v("こんにちは ぎっと\nこんばんは ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("💻 Commit する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git add hello.txt\n$ git status\n$ git commit\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[t("img",{attrs:{src:a(371),alt:"fixブランチでコミットした"}})]),s._v(" "),t("p",[s._v("💻 今いるfixブランチのファイルを確認する。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("これにより "),t("code",[s._v("fix")]),s._v("ブランチで Commit を積むことができました。\n"),t("code",[s._v("master")]),s._v("ブランチに戻るとどう見えるでしょう。")]),s._v(" "),t("h3",{attrs:{id:"_6-5-master-ブランチへ戻る"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-5-master-ブランチへ戻る"}},[s._v("#")]),s._v(' 6.5. "master"ブランチへ戻る')]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("master")]),s._v(" へ移動するために Checkout します。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout master\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("img",{attrs:{src:a(372),alt:"masterブランチに戻った"}})]),s._v(" "),t("p",[s._v('💻 "master"ブランチの履歴を見る。')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v('先ほどの「6.4. "fix"ブランチで Commit する」で行ったコミットは"fix"ブランチで行ったものですので、masterブランチでは見えません。')]),s._v(" "),t("p",[s._v("複数人で開発する場合には同時にいくつもの変更が行われていることがあります。\n"),t("code",[s._v("fix")]),s._v("ブランチで修正中ですが、並行して"),t("code",[s._v("master")]),s._v("ブランチでも変更を入れてみましょう。")]),s._v(" "),t("p",[s._v("💻 masterブランチで別のコミットをする")]),s._v(" "),t("div",{staticClass:"language-diff line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-diff"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\n"),t("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[t("span",{pre:!0,attrs:{class:"token prefix deleted"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("こんばんは ぎっと\n")])]),t("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[t("span",{pre:!0,attrs:{class:"token prefix inserted"}},[s._v("+")]),t("span",{pre:!0,attrs:{class:"token line"}},[s._v("おやすみ ぎっと\n")])])])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[t("img",{attrs:{src:a(373),alt:"masterブランチに戻った"}})]),s._v(" "),t("p",[s._v("💻 "),t("code",[s._v("master")]),s._v("と"),t("code",[s._v("fix")]),s._v("の2つのブランチを言ったり来たりして、ファイルの状態が変わることを確認しましょう。")]),s._v(" "),t("h3",{attrs:{id:"_6-6-マージする"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_6-6-マージする"}},[s._v("#")]),s._v(" 6.6. マージする")]),s._v(" "),t("p",[s._v("今いるブランチに他のブランチでの変更を取り込むことをマージ(merge)と呼びます。")]),s._v(" "),t("p",[s._v("修正が完了して問題がないことを完了したのでこの修正を"),t("code",[s._v("master")]),s._v("ブランチに取り込みます。\n"),t("code",[s._v("master")]),s._v('ブランチに "fix"ブランチの変更を取り込みます。')]),s._v(" "),t("p",[t("code",[s._v("master")]),s._v("ブランチの内容は")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう ぎっと\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("に"),t("code",[s._v("fix")]),s._v("ブランチの内容")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nこんばんは ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("を取り込みます。すると")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])]),t("p",[s._v("となるはずです。歴史は以下のようになります。")]),s._v(" "),t("p",[t("img",{attrs:{src:a(374),alt:"ブランチをマージする"}})]),s._v(" "),t("p",[s._v("ブランチをマージするには"),t("code",[s._v("git merge")]),s._v("コマンドを使います。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git merge <取り込みたいブランチ名>\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v('💻 "master"ブランチへ移動してから"fix"ブランチの変更内容を、メインである"master"ブランチへ取り込みましょう')]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git checkout master\n$ git merge fix\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("マージするときのコミットコメントはデフォルトでOKです。")]),s._v(" "),t("p",[s._v("💻 マージされたファイルがどのように変更されたのか確認してみましょう")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ git log\n$ git show\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[t("code",[s._v("fix")]),s._v("ブランチで行ったコミットが取り込まれているでしょうか?")]),s._v(" "),t("div",{staticClass:"custom-block tip"},[t("p",{staticClass:"custom-block-title"},[s._v("チェックポイント2 🏁")]),s._v(" "),t("p",[s._v("hello.txtが以下のようになっていれば正解です!")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("おはよう Git\nこんにちは ぎっと\nおやすみ ぎっと\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br")])])]),s._v(" "),t("p",[s._v("Git の基本操作を一通り流してやってみました。\nGit ハンズオンは以上で終了です。")]),s._v(" "),t("p",[s._v("次は "),t("a",{attrs:{href:"../github"}},[s._v("GitHub ハンズオン")]),s._v(" に進んでください。")]),s._v(" "),t("h2",{attrs:{id:"_7-参考文献"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_7-参考文献"}},[s._v("#")]),s._v(" 7. 参考文献")]),s._v(" "),t("p",[s._v("さらに高度な使い方を知りたい方は"),t("a",{attrs:{href:"https://git-scm.com/book/ja/v2",target:"_blank",rel:"noopener noreferrer"}},[s._v("Pro Git"),t("OutboundLink")],1),s._v("が便利です。日本語版が公開されています。")]),s._v(" "),t("p",[s._v("こんな説明じゃブランチがわからん!という人は "),t("a",{attrs:{href:"https://learngitbranching.js.org/?locale=ja",target:"_blank",rel:"noopener noreferrer"}},[s._v("Learn Git Branching (日本語版)"),t("OutboundLink")],1),s._v(" で練習できます。")]),s._v(" "),t("h3",{attrs:{id:"_7-1-guiクライアント"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_7-1-guiクライアント"}},[s._v("#")]),s._v(" 7.1. GUIクライアント")]),s._v(" "),t("p",[s._v("Gitには、機能が限定されますがGUIクライアントも用意されています。おすすめは以下の3つのクライアントです。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://desktop.github.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("GitHub Desktop (Win, macOS)"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://tortoisegit.org/",target:"_blank",rel:"noopener noreferrer"}},[s._v("TortoiseGit (Win)"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://www.sourcetreeapp.com/",target:"_blank",rel:"noopener noreferrer"}},[s._v("SourceTree (Win, macOS)"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("また各種統合開発環境にもGitを操作する機能が含まれています。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://code.visualstudio.com/docs/editor/versioncontrol",target:"_blank",rel:"noopener noreferrer"}},[s._v("Using Version Control in VS Code"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://pleiades.io/help/idea/using-git-integration.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("Git - ヘルプ | IntelliJ IDEA"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("これらのクライアントの利用も検討してください。")]),s._v(" "),t("credit-footer")],1)}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/13.6ba5b0da.js b/assets/js/13.dd6eb0fe.js similarity index 99% rename from assets/js/13.6ba5b0da.js rename to assets/js/13.dd6eb0fe.js index 64f042a2..645cf7f0 100644 --- a/assets/js/13.6ba5b0da.js +++ b/assets/js/13.dd6eb0fe.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{256:function(t,s,e){t.exports=e.p+"assets/img/fork-repo.e0dbd328.jpg"},279:function(t,s,e){t.exports=e.p+"assets/img/drone_first_test.31192e41.png"},280:function(t,s,e){t.exports=e.p+"assets/img/drone_steps.6a94640c.png"},281:function(t,s,e){t.exports=e.p+"assets/img/drone_test_failed.3ffdd2f3.png"},282:function(t,s,e){t.exports=e.p+"assets/img/drone_pull_request_button.39571d74.png"},283:function(t,s,e){t.exports=e.p+"assets/img/drone_pull_request_result.6e4f0582.png"},284:function(t,s,e){t.exports=e.p+"assets/img/drone_branch_protection.6e9707f7.png"},285:function(t,s,e){t.exports=e.p+"assets/img/drone_reject_merge.260c0651.png"},286:function(t,s,e){t.exports=e.p+"assets/img/drone_textlint_error.9c7cad75.png"},506:function(t,s,e){"use strict";e.r(s);var a=e(10),n=Object(a.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"drone-でciテスト・デプロイを回す"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#drone-でciテスト・デプロイを回す"}},[t._v("#")]),t._v(" drone でCIテスト・デプロイを回す")]),t._v(" "),s("h2",{attrs:{id:"_0-この講義について"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-この講義について"}},[t._v("#")]),t._v(" 0. この講義について")]),t._v(" "),s("h3",{attrs:{id:"_0-1-この講義の目的"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-この講義の目的"}},[t._v("#")]),t._v(" 0.1 この講義の目的")]),t._v(" "),s("p",[t._v("継続的インテグレーション(Continuous Integration)、継続的デリバリ(Continuous Delivery)について理解する。\ndrone を利用したCI/CDを体験し、自分のプロジェクトにCI/CDを自ら導入できるようにする。")]),t._v(" "),s("h3",{attrs:{id:"_0-2-ハンズオンの対象者"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-ハンズオンの対象者"}},[t._v("#")]),t._v(" 0.2 ハンズオンの対象者")]),t._v(" "),s("p",[t._v("これからプログラムを書く、またはテキストファイルによる設定ファイル、マニュアル、仕様書などを記述する可能性のある技術者を対象としています。")]),t._v(" "),s("p",[t._v("講義にあたって事前に以下の要件を満たすようにしてください。")]),t._v(" "),s("ul",[s("li",[t._v("YAMLの読み書きができること\n"),s("ul",[s("li",[t._v("知らない場合は"),s("a",{attrs:{href:"https://www.codeproject.com/Articles/1214409/Learn-YAML-in-five-minutes",target:"_blank",rel:"noopener noreferrer"}},[t._v("Learn YAML in five minutes!"),s("OutboundLink")],1),t._v("をご覧ください。")])])]),t._v(" "),s("li",[t._v("「Gitの使い方+GitHubを使った開発手法」を受講しておくこと\n"),s("ul",[s("li",[t._v("この講義の中では Git の操作に加え GitHub 上での操作も必要になります。アカウントがない場合は事前に用意してください。")])])])]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント1 🏁")]),t._v(" "),s("p",[t._v("Gitの使い方+GitHubを使った開発手法を受講しましたか?"),s("br"),t._v("\ngit clone, checkout, add, commit, push などを利用します。")])]),t._v(" "),s("h3",{attrs:{id:"_0-3-下準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-下準備"}},[t._v("#")]),t._v(" 0.3 下準備")]),t._v(" "),s("ul",[s("li",[t._v("Gitを利用できる環境を準備してください。")]),t._v(" "),s("li",[t._v("お好みのテキストエディタを準備してください。\n"),s("ul",[s("li",[t._v("この講義では"),s("a",{attrs:{href:"https://azure.microsoft.com/ja-jp/products/visual-studio-code/",target:"_blank",rel:"noopener noreferrer"}},[t._v("VSCode"),s("OutboundLink")],1),t._v("を推奨します。\n"),s("a",{attrs:{href:"https://atom.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Atom"),s("OutboundLink")],1),t._v("や"),s("a",{attrs:{href:"https://www.sublimetext.com/3",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sublime Text"),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://notepad-plus-plus.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nodepad++"),s("OutboundLink")],1),t._v("を使ってもかまいません。Vimに慣れている人はVimを使ってもよいです。\nメモ帳、サクラエディタ、TeraPadは非推奨です。")])])])]),t._v(" "),s("h3",{attrs:{id:"_0-4-この資料のお約束"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-4-この資料のお約束"}},[t._v("#")]),t._v(" 0.4. この資料のお約束")]),t._v(" "),s("p",[t._v("💻 は自分で操作する箇所を示しています。")]),t._v(" "),s("p",[t._v("<ほげほげ> で囲まれている部分は自分の設定値で置き換えてください。たとえば")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git clone <リモートリポジトリのアドレス>\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("と記載されている箇所は")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git clone git@github.com:iij/bootcamp.git\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("というように置き換えてください。")]),t._v(" "),s("h2",{attrs:{id:"_1-継続的インテグレーション、継続的デリバリとは"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-継続的インテグレーション、継続的デリバリとは"}},[t._v("#")]),t._v(" 1. 継続的インテグレーション、継続的デリバリとは")]),t._v(" "),s("p",[t._v("継続的インテグレーション(Continuous Integration、以下CI)とは、\nアプリケーションのリリースサイクルにおいてビルドやテストなどを自動化し、\n継続的に実行することで品質改善や納期短縮を実現するための方法です。")]),t._v(" "),s("p",[t._v("もしかしたら自分のプロジェクトがそうかもれませんが、プログラミングは意外と手作業の多い分野でした。\nしかしながら手作業でビルド、テストをしていると不具合が含まれていても発覚するのが遅くなり、手戻りが大きくなってしまいます。\nそこでビルドやテストを自動化し、コードがpushされたらすぐに実行することで早期に不具合を見つけようというのがCIです。\nまた世の中にはビルドが難しいプロダクトというのも多数存在しますので、自動化されているということは開発メンバーを追加するのも楽になります。")]),t._v(" "),s("p",[t._v("継続的デリバリ(Continuous Delivery、以下CD)とはCIをさらに進めてユーザーに製品を届けるまでのリリースプロセス全体を自動化し、\n"),s("strong",[t._v("継続的に顧客に価値を届ける")]),t._v("ことを目的とした手法です。")]),t._v(" "),s("p",[t._v("CI/CDを導入した場合、コードをコミットするとビルドが走り、ユニットテストを通して、コードがテスト環境にデプロイされます。その後結合テスト、\nシステムテストを行い、必要であれば承認後、本番環境にデプロイされます。")]),t._v(" "),s("h2",{attrs:{id:"_2-droneとは"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-droneとは"}},[t._v("#")]),t._v(" 2. droneとは")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone"),s("OutboundLink")],1),t._v(" とはdockerをベースとしたCI/CDのためのプラットフォームです。\nIIJ社内ではdrone v1.0を提供しています。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("社内のプライベートな環境で使えるdroneが用意されていることがあります。\n講師の指示がある場合はそちらの環境を利用しましょう。")])]),t._v(" "),s("ul",[s("li",[t._v("サイト: "),s("a",{attrs:{href:"https://cloud.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://cloud.drone.io/"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("ドキュメント: "),s("a",{attrs:{href:"https://docs.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://docs.drone.io/"),s("OutboundLink")],1)])]),t._v(" "),s("p",[t._v("GitHubと連携して簡単に設定を行うことができ、設定もyamlに記載するシンプルなもので、dockerベースのため環境構築も簡単に行うことができます。")]),t._v(" "),s("h3",{attrs:{id:"_2-1-とりあえず初めてみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-とりあえず初めてみる"}},[t._v("#")]),t._v(" 2.1. とりあえず初めてみる")]),t._v(" "),s("h4",{attrs:{id:"_2-1-1-droneの設定を有効化する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-1-droneの設定を有効化する"}},[t._v("#")]),t._v(" 2.1.1. droneの設定を有効化する")]),t._v(" "),s("p",[t._v("このハンズオンのためにCI/CDを行うためのサンプルリポジトリを "),s("a",{attrs:{href:"https://github.com/iij/drone-exercise",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/iij/drone-exercise"),s("OutboundLink")],1),t._v(" に用意しています。")]),t._v(" "),s("p",[t._v("💻 GitHub上で操作し、作業用リポジトリを作成してください。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(256),alt:"droneで最初のテスト"}})]),t._v(" "),s("p",[t._v("上記リポジトリを開いて「Use this template」を押してください。"),s("br"),t._v("\nリポジトリ名は「"),s("code",[t._v("drone-exercise-")]),t._v("」にしましょう。"),s("br"),t._v("\nほかの設定値はデフォルトで良いです。")]),t._v(" "),s("p",[t._v("ここで作成したリポジトリに対して操作をしていきます。")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("Use this template が表示されていない場合は正しくログインできているか確認してください。"),s("br"),t._v("\n講師から repository を作成する organization が指示されていれば、それに従ってください。")])]),t._v(" "),s("p",[t._v("droneはGitHub上のコミットやpushといったイベントが発生するとそれに応じて自動的に処理が走るようになっています。\nこれはWebhookというしくみを用いて実現されていますが、droneを使う前にこの設定が必要です。")]),t._v(" "),s("p",[t._v("💻 droneにリポジトリを登録する。")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://cloud.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://cloud.drone.io/"),s("OutboundLink")],1),t._v(" では 新規のユーザー登録を行っていません。"),s("br"),t._v("\nそのため、以下の手順を実施するためには "),s("a",{attrs:{href:"http://drone.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone.io"),s("OutboundLink")],1),t._v(" の 構築が必要です。"),s("br"),t._v("\n講師は接続先を案内してください。")])]),t._v(" "),s("p",[s("a",{attrs:{href:"http://xn--drone-f83dqcwesos420avc3aymzhv8g.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("講師に案内されたdrone.io"),s("OutboundLink")],1),t._v(" にログインしてください。")]),t._v(" "),s("p",[t._v("初回のログインでは OAuth の連携の許可が必要になるかもしれません。")]),t._v(" "),s("p",[t._v("Repositories の リストから「自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v("」を探してリポジトリ名をクリックし詳細ページを開きましょう。")]),t._v(" "),s("p",[t._v("見つからない場合は「SYNC」ボタンを押してから探してください。")]),t._v(" "),s("p",[t._v("「SETTINGS」タブから「ACTIVATE REPOSITORY」をクリックすると自動で設定が行われ、設定画面が表示されます。")]),t._v(" "),s("p",[t._v("これでdroneを利用する準備が整いました。")]),t._v(" "),s("h4",{attrs:{id:"_2-1-2-droneでテストを実行する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-2-droneでテストを実行する"}},[t._v("#")]),t._v(" 2.1.2. droneでテストを実行する")]),t._v(" "),s("p",[t._v("💻 作成した作業用リポジトリ(自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v(")をローカルにgit cloneしてください。")]),t._v(" "),s("p",[t._v("このリポジトリにはすでにdroneの設定ファイルが置かれています。\n適当に"),s("code",[t._v("README.md")]),t._v("を編集してコミット、pushしてみましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("おさらいです。 編集したあとは git add でステージング したのち commit && push となります。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('date >> README.md\ngit add README.md\ngit commit -m "update README.md"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])])]),t._v(" "),s("p",[t._v("GitHub に push してしばらくすると drone で テストが実行されます。")]),t._v(" "),s("p",[t._v("先程開いた droneの「自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v("」の 詳細ページから「ACTIVITY FEED」タブを開くとテストの実行ログが表示されます。")]),t._v(" "),s("p",[t._v("クリックして 実行ログを読むとどのようにテストが実行されているかが分かります。")]),t._v(" "),s("p",[t._v("このリポジトリにはRubyで書かれたプログラムと、Ruby用のテストフレームワークである"),s("a",{attrs:{href:"https://rspec.info/",target:"_blank",rel:"noopener noreferrer"}},[t._v("RSpec"),s("OutboundLink")],1),t._v("で\n書かれたテストが置かれています。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(279),alt:"droneで最初のテスト"}})]),t._v(" "),s("p",[t._v("図を見ると、 clone と test の step からなるとわかります。")]),t._v(" "),s("p",[t._v("それぞれクリックすると各 step の詳細が表示されます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント2 🏁")]),t._v(" "),s("p",[t._v("「test」ではどういうメッセージが出力されたでしょうか?")])]),t._v(" "),s("h4",{attrs:{id:"_2-1-3-webhookの設定確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-3-webhookの設定確認"}},[t._v("#")]),t._v(" 2.1.3 Webhookの設定確認")]),t._v(" "),s("p",[t._v("drone と GitHub の連携には Webhook を利用しています。")]),t._v(" "),s("p",[t._v("デフォルトでは"),s("code",[t._v("pr")]),t._v("と"),s("code",[t._v("push")]),t._v("の2つが登録されています。")]),t._v(" "),s("p",[s("code",[t._v("pr")]),t._v("を指定すると、Pull Requestをオープンしたとき、または既存のPRへpushしたときにテストが実行されます。\n"),s("code",[t._v("push")]),t._v(" を指定すると、"),s("code",[t._v("git push")]),t._v(" したときにテストが実行されます。")]),t._v(" "),s("p",[t._v("この設定は 「Settings」->「Hooks」->「Webhooks」-> droneのエントリ -> Edit で確認でき、")]),t._v(" "),s("p",[t._v("設定画面最下部の「Recent Deliveries」では実際に発行されたWebhookを確認 & 再送信できます。")]),t._v(" "),s("h2",{attrs:{id:"_3-droneの基本的な設定"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-droneの基本的な設定"}},[t._v("#")]),t._v(" 3. droneの基本的な設定")]),t._v(" "),s("p",[t._v("drone設定の基本は、どういった環境で、どのようなコマンドを実行するかということを記述することです。")]),t._v(" "),s("p",[t._v("設定はKubernetesライクな書き方になっていますので、Kubernetesの知識があれば読みやすいです。")]),t._v(" "),s("p",[t._v("droneはバージョンによって設定ファイルの書き方が異なりますので、\n既存のプロジェクトを編集するときは気を付けてください。")]),t._v(" "),s("p",[t._v("droneの設定はデフォルトでリポジトリの一番上の階層に"),s("code",[t._v(".drone.yml")]),t._v("という名前で置きます。")]),t._v(" "),s("p",[t._v("2.1.2 でcloneしたリポジトリの"),s("code",[t._v(".drone.yml")]),t._v("を見てみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle install\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" rspec\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("各項目について解説していきます。")]),t._v(" "),s("h3",{attrs:{id:"_3-1-pipeline"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-pipeline"}},[t._v("#")]),t._v(" 3.1. Pipeline")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("一連のテスト実行の流れを"),s("code",[t._v("Pipeline")]),t._v("と呼びます。")]),t._v(" "),s("p",[t._v("まずyamlの先頭で"),s("code",[t._v("kind: pipeline")]),t._v("と記載し、この下に書かれる設定値がPipelineのものであることを宣言します。\nただIIJの環境では"),s("code",[t._v("Pipeline")]),t._v("以外の設定は利用できませんのでこの"),s("code",[t._v("kind")]),t._v("と"),s("code",[t._v("name")]),t._v("は固定になります。")]),t._v(" "),s("p",[s("code",[t._v("Pipeline")]),t._v("は複数の"),s("code",[t._v("Step")]),t._v("で構成されます。")]),t._v(" "),s("h3",{attrs:{id:"_3-2-steps"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-steps"}},[t._v("#")]),t._v(" 3.2. Steps")]),t._v(" "),s("p",[t._v("ひとつのPipelineで複数のテスト("),s("code",[t._v("Step")]),t._v(")を実行できます。")]),t._v(" "),s("p",[t._v("各"),s("code",[t._v("Step")]),t._v("は別々のdockerコンテナで実行され、各テストは独立した環境でテストできます。")]),t._v(" "),s("p",[t._v("UI上では各"),s("code",[t._v("Step")]),t._v("ごとに結果が分けて表示され、"),s("code",[t._v("name")]),t._v("で名前を付けることができ、これはUI上に表示されます。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(280),alt:"Stepの表示"}})]),t._v(" "),s("p",[s("code",[t._v("image")]),t._v(" はテストに利用するdockerイメージを指定します。")]),t._v(" "),s("p",[s("code",[t._v("image: ruby")]),t._v(" と指定した場合はDocker Hubの"),s("a",{attrs:{href:"https://hub.docker.com/_/ruby",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ruby Official Image"),s("OutboundLink")],1),t._v("が利用されます。\n素性のわからないイメージを利用することはやめましょう。")]),t._v(" "),s("p",[t._v("また、"),s("code",[t._v("image: ruby:3.1.2")]),t._v(" のようにタグを指定して、特定のバージョンを利用できるイメージもありますが意図せず更新される場合があります。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("プライベートなDockerイメージ置き場を自分で作成することもできます。")])]),t._v(" "),s("p",[s("code",[t._v("commands")]),t._v(" にはコンテナ内で実行するコマンドを記述します。")]),t._v(" "),s("p",[s("code",[t._v("bundle install")]),t._v(" ではテスト実行に必要なライブラリをインストールしていて、"),s("code",[t._v("rspec")]),t._v("でテストを実行しています。")]),t._v(" "),s("p",[t._v("各テストが成功したかどうかは各コマンドのExit Codeを見ていて、Code 0以外ではテストは中断され失敗となります。\nテストが失敗すると以下のような表示になります。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(281),alt:"テスト失敗時の表示"}})]),t._v(" "),s("h2",{attrs:{id:"_4-pull-requestと組み合わせる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-pull-requestと組み合わせる"}},[t._v("#")]),t._v(" 4. Pull Requestと組み合わせる")]),t._v(" "),s("p",[t._v("droneを設定した状態でPull Requestを作成するとどうなるでしょうか。")]),t._v(" "),s("p",[t._v("💻 意図的にテストが失敗するようにコードを修正し、Pull Requestを作成してみましょう。")]),t._v(" "),s("ol",[s("li",[t._v("まず、別の branch へ checkout します")])]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git checkout -b feature/text-error\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("ol",{attrs:{start:"2"}},[s("li",[t._v("実装である"),s("code",[t._v("hello_world.rb")]),t._v("を以下のように書き換えてみます。")])]),t._v(" "),s("div",{staticClass:"language-diff line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-diff"}},[s("code",[s("span",{pre:!0,attrs:{class:"token unchanged"}},[s("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" def world\n")])]),s("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[s("span",{pre:!0,attrs:{class:"token prefix deleted"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" 'Hello World'\n")])]),s("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[s("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" 'Goodby World'\n")])]),s("span",{pre:!0,attrs:{class:"token unchanged"}},[s("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" end\n")])])])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("ol",{attrs:{start:"3"}},[s("li",[t._v("編集した内容を commit し push します。")])]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add hello_world.rb\ngit commit -m "goodby"\ngit push origin feature/text-error\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("💻 GitHub を開いてPull Requestを作成しましょう。")]),t._v(" "),s("p",[t._v("別のbranch に push した内容を develop branch などへ取り込んでもらうためのリクエストを Pull Request(PR) と呼びます。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(282),alt:"Pull Requestを作成しましょう"}})]),t._v(" "),s("p",[t._v("もし、作業リポジトリを fork して作成した場合 PR の送り先が fork 元 repository になっています。")]),t._v(" "),s("p",[t._v("その時は 自分のrepository に PR を送るように base repository (左側) の 表記を見直してください。")]),t._v(" "),s("p",[t._v("無事PRを作成できた場合 PRのページへ遷移します。")]),t._v(" "),s("p",[t._v("ページ下部にdroneのテスト結果が表示されています。")]),t._v(" "),s("p",[t._v("一目でテストが失敗していることがわかるでしょう。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(283),alt:"Pull Requestに表示されたdroneの結果"}})]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント3 🏁")]),t._v(" "),s("p",[t._v("Pull Request は作成できましたか?"),s("br"),t._v(" "),s("a",{attrs:{href:"http://drone.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone.io"),s("OutboundLink")],1),t._v(" は動作しましたか?"),s("br"),t._v("\nテストが失敗しましたか?")])]),t._v(" "),s("h3",{attrs:{id:"_4-1-テストが失敗したらマージできないようにしたい"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-テストが失敗したらマージできないようにしたい"}},[t._v("#")]),t._v(" 4.1. テストが失敗したらマージできないようにしたい")]),t._v(" "),s("p",[t._v("さて、 先程のPRではテストに失敗してしまいました。")]),t._v(" "),s("p",[t._v("この状態でもMergeボタンを押すことは可能ですが、普通は押されたくないはずです。\nこの挙動はGitHubの設定画面から変更できます。")]),t._v(" "),s("p",[t._v("💻 テストが通ったときだけマージできるように設定する")]),t._v(" "),s("ol",[s("li",[t._v("「Settings」->「Branches」->「Branch protection rules」->「Add rule」を押し、")]),t._v(" "),s("li",[t._v("「Branch name pattern」に「master」と記入し、")]),t._v(" "),s("li",[t._v("「Include administrators」にチェックを入れます。")]),t._v(" "),s("li",[t._v("「Require status checks to pass before merging」にチェックを入れて")]),t._v(" "),s("li",[t._v("「Status checks found in the last week for this repository」に出ている\n「continuous-integration/drone/pr」と\n「continuous-integration/drone/push」にチェックを入れます。")]),t._v(" "),s("li",[t._v("「Create」します。")])]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("もし、continuous-integration/drone/pr が見つからない場合"),s("br"),t._v("\n先ほど作成したPRによる drone のテストがうまく動いていないかもしれません。"),s("br"),t._v("\nfork した場合は PR の作成先を確認する必要があります。"),s("br"),t._v("\nPR の作成先が間違っているかもしれません。見直してください。")])]),t._v(" "),s("p",[s("img",{attrs:{src:e(284),alt:"Branch protection rules"}})]),t._v(" "),s("p",[t._v("先程作成したPull Requestのページに戻るとマージボタンが押せなくなっています。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(285),alt:"マージできない状態"}})]),t._v(" "),s("p",[t._v("これは複数人で開発するときには便利な機能です。")]),t._v(" "),s("p",[t._v("このあとmasterブランチを利用しますのでBranch protection rulesは削除しておきましょう。")]),t._v(" "),s("p",[t._v("💻 Branch protection rules の一覧ページで"),s("code",[t._v("master")]),t._v("と名前がついたルールの"),s("code",[t._v("delete")]),t._v("ボタンを押す")]),t._v(" "),s("p",[t._v("💻 この後項目のためにmasterブランチに戻っておきましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("$ git checkout master\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント4 🏁")]),t._v(" "),s("p",[t._v("マージボタンが押せなくなったのはなぜですか?")])]),t._v(" "),s("h2",{attrs:{id:"_5-さまざまなプラグイン"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-さまざまなプラグイン"}},[t._v("#")]),t._v(" 5. さまざまなプラグイン")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://plugins.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("droneには様々なプラグインが用意されています。"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("主に外部と連携する機能が用意されています。\n後述する利用のしかたからも分かるとおり plugin は 単なる docker コンテナであるため、自分で開発することもできます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Plugins are just Docker containers which means you can write plugins in any programming language that runs inside a container. You can even create plugins using simple bash scripting.\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("blockquote",[s("p",[s("a",{attrs:{href:"https://docs.drone.io/plugins/overview/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://docs.drone.io/plugins/overview/"),s("OutboundLink")],1),t._v(" より引用")])]),t._v(" "),s("h3",{attrs:{id:"_5-1-キャッシュプラグイン"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-キャッシュプラグイン"}},[t._v("#")]),t._v(" 5.1. キャッシュプラグイン")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("この項目はS3互換のオブジェクトストレージが必要です。\n講師は接続先を案内してください。")])]),t._v(" "),s("p",[t._v("これまでの例ではテストを実行するときに必要なライブラリを"),s("code",[t._v("bundle install")]),t._v("で事前にダウンロードしてから実行していました。\nしかし毎回ダウンロードしていたのではテスト実行に時間がかかりますし、ネットワークの無駄です。")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://plugins.drone.io/drone-plugins/drone-s3-cache/",target:"_blank",rel:"noopener noreferrer"}},[t._v("s3-cache"),s("OutboundLink")],1),t._v("プラグインを使うと特定のディレクトリを\n"),s("a",{attrs:{href:"https://aws.amazon.com/jp/s3/",target:"_blank",rel:"noopener noreferrer"}},[t._v("S3"),s("OutboundLink")],1),t._v("に保存し、テストのたびに復元してくれる機能を提供します。")]),t._v(" "),s("h4",{attrs:{id:"_5-1-1-ライブラリの保存場所を変更する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-1-ライブラリの保存場所を変更する"}},[t._v("#")]),t._v(" 5.1.1. ライブラリの保存場所を変更する")]),t._v(" "),s("p",[t._v("パッケージマネージャーによってはリポジトリの中ではなく、システムの特別な場所に配置するものがあります。\ns3-cacheプラグインはリポジトリ内にあるファイルしかキャッシュできません。")]),t._v(" "),s("p",[t._v("nodejsのパッケージマネージャーであるnpmはデフォルトでリポジトリ直下にライブラリを配置しますが、\nRubyのパッケージマネージャーであるbundlerはシステム領域にライブラリを保存するため、\nそのままではキャッシュさせることができません。\nほとんどの場合、パッケージマネージャーのオプションで保存場所を変更できますので、\nRubyを例に設定してみましょう。")]),t._v(" "),s("p",[t._v("Rubyのパッケージマネージャーであるbundlerは"),s("code",[t._v("--path")]),t._v("オプションで保存場所を指定できます。")]),t._v(" "),s("p",[s("code",[t._v("drone.yaml")]),t._v(" で 実行している "),s("code",[t._v("bundle install")]),t._v(" にオプションを渡し 一般的によく使われる"),s("code",[t._v("vendor/bundle")]),t._v("に保存するように変更してください。")]),t._v(" "),s("p",[t._v("💻 パッケージの保存先を変更する")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" - name: test\n image: ruby:2.6.2\n commands:\n - bundle install --path vendor/bundle\n - bundle exec rspec\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br")])]),s("h4",{attrs:{id:"_5-1-2-ライブラリをキャッシュさせてみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-2-ライブラリをキャッシュさせてみる"}},[t._v("#")]),t._v(" 5.1.2. ライブラリをキャッシュさせてみる")]),t._v(" "),s("p",[t._v("さっそくキャッシュさせてみましょう。")]),t._v(" "),s("p",[t._v("このプラグインはキャッシュしたデータを戻す"),s("code",[t._v("restore")]),t._v("と、キャッシュを行う"),s("code",[t._v("rebuild")]),t._v("の機能があります。")]),t._v(" "),s("p",[s("code",[t._v(".drone.yml")]),t._v("を編集してキャッシュを組み込んでみましょう。\n"),s("code",[t._v("rebuild")]),t._v("ステップで"),s("code",[t._v("vendor/bundle")]),t._v("ディレクトリをキャッシュし、\n"),s("code",[t._v("restore")]),t._v("ステップでキャッシュされたものを戻します。")]),t._v(" "),s("p",[s("code",[t._v("test")]),t._v("Stepの前後に、"),s("code",[t._v("restore")]),t._v("と"),s("code",[t._v("rebuild")]),t._v("を追加します。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("以下の設定は各環境で用意された接続先へ値を変更してください。")]),t._v(" "),s("p",[t._v("<変数名>で書かれた場所を適切な値で置き換えてください。")])]),t._v(" "),s("p",[t._v("💻 パッケージをキャッシュするように変更する")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" restore\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" plugins/s3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("cache\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("settings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("pull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("endpoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("access_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("secret_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("restore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("path vendor/bundle\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rspec\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" rebuild\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" plugins/s3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("cache\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("settings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("pull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("endpoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("access_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("secret_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("rebuild")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mount")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" vendor/bundle\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br"),s("span",{staticClass:"line-number"},[t._v("26")]),s("br")])]),s("p",[t._v("💻 コミットして実行してみましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add .drone.yml\ngit commit -m "Cache導入"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("droneのUI上で最新の実行ログを開いて見ましょう。\n"),s("code",[t._v("restore")]),t._v("と"),s("code",[t._v("rebuild")]),t._v("のステップが増えていることを確認してください。")]),t._v(" "),s("p",[t._v("1回目はキャッシュされてないので何も起きませんが、2回目からはキャッシュが使われるので実行が早くなります。\n1回目の実行時間を確認してから、以下のように2回目のテストを実行してみてください。")]),t._v(" "),s("p",[s("code",[t._v("--allow-empty")]),t._v(" はファイルを変更していなくてもコミットを作ることができるオプションです。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git commit --allow-empty -m "Cacheの効果を確認する"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("このキャッシュを利用する操作は drone で完結しない処理です。"),s("br"),t._v("\nもしオブジェクトストレージ側にトラブルがあれば 処理が長時間に及ぶ可能性があります。")]),t._v(" "),s("p",[t._v("また、drone 上の ジョブの同時実行数には限りがある場合があります。"),s("br"),t._v("\n処理が長時間に渡る場合は drone 上のジョブ実行結果の確認画面から キャンセルができます")])]),t._v(" "),s("p",[t._v("💻 テスト実行が早くなっていることを確認しましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント5 🏁")]),t._v(" "),s("p",[t._v("テストが速くなったのはなぜですか?")])]),t._v(" "),s("h2",{attrs:{id:"_6-さまざまな応用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-さまざまな応用"}},[t._v("#")]),t._v(" 6. さまざまな応用")]),t._v(" "),s("h3",{attrs:{id:"_6-1-text-lintを使った日本語チェックの例"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-1-text-lintを使った日本語チェックの例"}},[t._v("#")]),t._v(" 6.1. Text Lintを使った日本語チェックの例")]),t._v(" "),s("p",[t._v("droneはプログラムにしか使えないものでしょうか。そうではありません。\ndroneは何でも動かすことができますから、テストをすることだけが仕事ではありません。")]),t._v(" "),s("p",[t._v("ここでは自然言語のチェックを行う "),s("a",{attrs:{href:"https://textlint.github.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("textlint"),s("OutboundLink")],1),t._v(" を使った例を紹介します。")]),t._v(" "),s("p",[t._v("💻 stepsに以下の項目を追加してみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" textlint\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" node\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" npm install textlint\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" npm install textlint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rule"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("preset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("ja"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("technical"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("writing\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" $(npm bin)/textlint "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("format pretty"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("error "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("preset ja"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("technical"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("writing README.md\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("textlintはnodejsで動作しますので、イメージにnodeを指定します。\ntextlintはフレームワークのみでこれ単体で動かすことはできません。どういったものをチェックするかというルールは別に定義しなければいけません。\nここでは日本語の技術文書を書くうえで必要ないくつかのルールをまとめた\n"),s("a",{attrs:{href:"https://github.com/textlint-ja/textlint-rule-preset-ja-technical-writing",target:"_blank",rel:"noopener noreferrer"}},[t._v("textlint-rule-preset-ja-technical-writing"),s("OutboundLink")],1),t._v("\nを利用します。試しに "),s("code",[t._v("README.md")]),t._v("をチェックしてみましょう。")]),t._v(" "),s("p",[t._v("💻 README.mdをTextlintでチェックする。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add .drone.yml\ngit commit -m "textlintによるチェック"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[s("img",{attrs:{src:e(286),alt:"textlintのエラー"}})]),t._v(" "),s("p",[t._v("このようにチェックする対象はプログラムに限りませんので、マニュアルなどのドキュメントのチェックなどにも活用できます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント6 🏁")]),t._v(" "),s("p",[t._v("droneが利用できる事例としてふさわしいものはどれですか?")])]),t._v(" "),s("h3",{attrs:{id:"_6-2-services"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-services"}},[t._v("#")]),t._v(" 6.2 Services")]),t._v(" "),s("p",[t._v("単純なスクリプトやライブラリのテストはこれだけでも十分にdroneでテストできます。")]),t._v(" "),s("p",[t._v("ではデータベース使ったテストはできるでしょうか。")]),t._v(" "),s("p",[t._v("データベースのテストをするならデータベースのプロセスが上がっている必要があります。"),s("br"),t._v("\nでも1つのコンテナでアプリケーションと一緒にデータベースも一緒に立ち上げたくないですよね。")]),t._v(" "),s("p",[t._v("そのために"),s("code",[t._v("Service")]),t._v("というしくみがあります。"),s("br"),t._v("\n同時に複数のコンテナを立ち上げて待機させておき、テスト中利用できます。")]),t._v(" "),s("p",[t._v("サンプルとしてRuby on Rails+MySQLで構成されたアプリケーションを用意しました。")]),t._v(" "),s("p",[t._v("💻 "),s("a",{attrs:{href:"https://github.com/iij/drone-exercise-rails",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/iij/drone-exercise-rails"),s("OutboundLink")],1),t._v(" から 作業用リポジトリを作成し、git cloneしてください。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(256),alt:"rails テスト"}})]),t._v(" "),s("p",[t._v("上記リポジトリを開いて「Use this template」を押してください。")]),t._v(" "),s("p",[t._v("リポジトリ名は「"),s("code",[t._v("drone-exercise-rails-")]),t._v("」にしましょう。"),s("br"),t._v("\nほかの設定値はデフォルトで良いです。")]),t._v(" "),s("p",[t._v("ここで作成したリポジトリに対して操作をしていきます。")]),t._v(" "),s("p",[t._v("Ruby on RailsはWebアプリケーションを作るためのRuby製フレームワークです。\nデータの保存にMySQLなどのデータベースを利用できます。")]),t._v(" "),s("p",[t._v("標準的なWebアプリケーションではデータベースなどの外部サービスにデータを保存し、それを読み取って加工して表示するという動作が多く、\nテストするときもデータベースが動いている必要があります。")]),t._v(" "),s("p",[t._v("上記リポジトリにはテストを行うだけの "),s("code",[t._v(".drone.yml")]),t._v(" が含まれています。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("environment")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("RAILS_ENV")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 実行に必要なライブラリをインストールする")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rails db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("reset "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テスト用のデータベース、テーブルを作成する")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rails test "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テストを実行する")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("p",[t._v("💻 まずはこの状態でテストを実行し、結果を見てみましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("新しいrepository への drone の 有効のしかた"),s("br"),t._v("\n内容の変更を伴わないcommit をする方法を思い出してください。")])]),t._v(" "),s("p",[t._v("ちなみにテストは "),s("code",[t._v("test/models/user_test.rb")]),t._v(" に書いてあります。")]),t._v(" "),s("p",[t._v("この状態ではデータベースが動いていないのでテストが成功しません。")]),t._v(" "),s("p",[t._v("テストしている間横で何か動かしておきたいという場合には "),s("code",[t._v("Service")]),t._v(" を使います。\n今回はMySQLを使いますが、"),s("a",{attrs:{href:"https://hub.docker.com/_/mysql",target:"_blank",rel:"noopener noreferrer"}},[t._v("MySQLは公式でdockerイメージが提供されています"),s("OutboundLink")],1),t._v("のでこれを利用します。")]),t._v(" "),s("p",[t._v("💻 以下の項目を"),s("code",[t._v(".drone.yml")]),t._v("に追加してください。")]),t._v(" "),s("p",[t._v("kind, name, steps と同じ高さでよいです(services の左側にスペースはいりません)")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("services")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" db\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" mysql"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("8.0.16\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("command")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"--default-authentication-plugin=mysql_native_password"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# MySQL8.0のデフォルト認証方式にRailsが対応していないため変更")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("environment")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("MYSQL_ALLOW_EMPTY_PASSWORD")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'yes'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テスト用にパスワードなしで接続できるようにする")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[s("code",[t._v("name")]),t._v(" で名前をつけて "),s("code",[t._v("image")]),t._v(" で使用するdockerイメージを指定します。")]),t._v(" "),s("p",[t._v("Railsではデータベースの設定を"),s("code",[t._v("config/database.yml")]),t._v("から読み込みます。"),s("br"),t._v("\ndroneで設定したデータベースへ接続するための設定値を見てみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("test")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("<<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token important"}},[t._v("*default")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("host")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" db\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3306")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("socket")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token null important"}},[t._v("null")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("database")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" drone"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("exercise"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rails_test\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("このファイルで接続先MySQLサーバのホストを指定しているのですが、"),s("br"),t._v("\nここでは"),s("code",[t._v(".drone.yml")]),t._v("で指定した"),s("code",[t._v("db")]),t._v("がホスト名になっていて、この名前で接続できます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント7 🏁")]),t._v(" "),s("p",[t._v("テスト実行中にデータベースはどこで実行されているでしょうか?")])]),t._v(" "),s("h2",{attrs:{id:"_8-参考情報"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_8-参考情報"}},[t._v("#")]),t._v(" 8. 参考情報")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://docs.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone Documentation"),s("OutboundLink")],1)])]),t._v(" "),s("h2",{attrs:{id:"続き"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#続き"}},[t._v("#")]),t._v(" 続き")]),t._v(" "),s("ul",[s("li",[s("RouterLink",{attrs:{to:"/cicd_infra/github_actions/"}},[t._v("GitHub Actions でCIテスト・デプロイを回す")])],1)])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{256:function(t,s,e){t.exports=e.p+"assets/img/fork-repo.e0dbd328.jpg"},279:function(t,s,e){t.exports=e.p+"assets/img/drone_first_test.31192e41.png"},280:function(t,s,e){t.exports=e.p+"assets/img/drone_steps.6a94640c.png"},281:function(t,s,e){t.exports=e.p+"assets/img/drone_test_failed.3ffdd2f3.png"},282:function(t,s,e){t.exports=e.p+"assets/img/drone_pull_request_button.39571d74.png"},283:function(t,s,e){t.exports=e.p+"assets/img/drone_pull_request_result.6e4f0582.png"},284:function(t,s,e){t.exports=e.p+"assets/img/drone_branch_protection.6e9707f7.png"},285:function(t,s,e){t.exports=e.p+"assets/img/drone_reject_merge.260c0651.png"},286:function(t,s,e){t.exports=e.p+"assets/img/drone_textlint_error.9c7cad75.png"},507:function(t,s,e){"use strict";e.r(s);var a=e(10),n=Object(a.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"drone-でciテスト・デプロイを回す"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#drone-でciテスト・デプロイを回す"}},[t._v("#")]),t._v(" drone でCIテスト・デプロイを回す")]),t._v(" "),s("h2",{attrs:{id:"_0-この講義について"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-この講義について"}},[t._v("#")]),t._v(" 0. この講義について")]),t._v(" "),s("h3",{attrs:{id:"_0-1-この講義の目的"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-この講義の目的"}},[t._v("#")]),t._v(" 0.1 この講義の目的")]),t._v(" "),s("p",[t._v("継続的インテグレーション(Continuous Integration)、継続的デリバリ(Continuous Delivery)について理解する。\ndrone を利用したCI/CDを体験し、自分のプロジェクトにCI/CDを自ら導入できるようにする。")]),t._v(" "),s("h3",{attrs:{id:"_0-2-ハンズオンの対象者"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-ハンズオンの対象者"}},[t._v("#")]),t._v(" 0.2 ハンズオンの対象者")]),t._v(" "),s("p",[t._v("これからプログラムを書く、またはテキストファイルによる設定ファイル、マニュアル、仕様書などを記述する可能性のある技術者を対象としています。")]),t._v(" "),s("p",[t._v("講義にあたって事前に以下の要件を満たすようにしてください。")]),t._v(" "),s("ul",[s("li",[t._v("YAMLの読み書きができること\n"),s("ul",[s("li",[t._v("知らない場合は"),s("a",{attrs:{href:"https://www.codeproject.com/Articles/1214409/Learn-YAML-in-five-minutes",target:"_blank",rel:"noopener noreferrer"}},[t._v("Learn YAML in five minutes!"),s("OutboundLink")],1),t._v("をご覧ください。")])])]),t._v(" "),s("li",[t._v("「Gitの使い方+GitHubを使った開発手法」を受講しておくこと\n"),s("ul",[s("li",[t._v("この講義の中では Git の操作に加え GitHub 上での操作も必要になります。アカウントがない場合は事前に用意してください。")])])])]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント1 🏁")]),t._v(" "),s("p",[t._v("Gitの使い方+GitHubを使った開発手法を受講しましたか?"),s("br"),t._v("\ngit clone, checkout, add, commit, push などを利用します。")])]),t._v(" "),s("h3",{attrs:{id:"_0-3-下準備"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-下準備"}},[t._v("#")]),t._v(" 0.3 下準備")]),t._v(" "),s("ul",[s("li",[t._v("Gitを利用できる環境を準備してください。")]),t._v(" "),s("li",[t._v("お好みのテキストエディタを準備してください。\n"),s("ul",[s("li",[t._v("この講義では"),s("a",{attrs:{href:"https://azure.microsoft.com/ja-jp/products/visual-studio-code/",target:"_blank",rel:"noopener noreferrer"}},[t._v("VSCode"),s("OutboundLink")],1),t._v("を推奨します。\n"),s("a",{attrs:{href:"https://atom.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Atom"),s("OutboundLink")],1),t._v("や"),s("a",{attrs:{href:"https://www.sublimetext.com/3",target:"_blank",rel:"noopener noreferrer"}},[t._v("Sublime Text"),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://notepad-plus-plus.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nodepad++"),s("OutboundLink")],1),t._v("を使ってもかまいません。Vimに慣れている人はVimを使ってもよいです。\nメモ帳、サクラエディタ、TeraPadは非推奨です。")])])])]),t._v(" "),s("h3",{attrs:{id:"_0-4-この資料のお約束"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_0-4-この資料のお約束"}},[t._v("#")]),t._v(" 0.4. この資料のお約束")]),t._v(" "),s("p",[t._v("💻 は自分で操作する箇所を示しています。")]),t._v(" "),s("p",[t._v("<ほげほげ> で囲まれている部分は自分の設定値で置き換えてください。たとえば")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git clone <リモートリポジトリのアドレス>\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("と記載されている箇所は")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git clone git@github.com:iij/bootcamp.git\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("p",[t._v("というように置き換えてください。")]),t._v(" "),s("h2",{attrs:{id:"_1-継続的インテグレーション、継続的デリバリとは"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-継続的インテグレーション、継続的デリバリとは"}},[t._v("#")]),t._v(" 1. 継続的インテグレーション、継続的デリバリとは")]),t._v(" "),s("p",[t._v("継続的インテグレーション(Continuous Integration、以下CI)とは、\nアプリケーションのリリースサイクルにおいてビルドやテストなどを自動化し、\n継続的に実行することで品質改善や納期短縮を実現するための方法です。")]),t._v(" "),s("p",[t._v("もしかしたら自分のプロジェクトがそうかもれませんが、プログラミングは意外と手作業の多い分野でした。\nしかしながら手作業でビルド、テストをしていると不具合が含まれていても発覚するのが遅くなり、手戻りが大きくなってしまいます。\nそこでビルドやテストを自動化し、コードがpushされたらすぐに実行することで早期に不具合を見つけようというのがCIです。\nまた世の中にはビルドが難しいプロダクトというのも多数存在しますので、自動化されているということは開発メンバーを追加するのも楽になります。")]),t._v(" "),s("p",[t._v("継続的デリバリ(Continuous Delivery、以下CD)とはCIをさらに進めてユーザーに製品を届けるまでのリリースプロセス全体を自動化し、\n"),s("strong",[t._v("継続的に顧客に価値を届ける")]),t._v("ことを目的とした手法です。")]),t._v(" "),s("p",[t._v("CI/CDを導入した場合、コードをコミットするとビルドが走り、ユニットテストを通して、コードがテスト環境にデプロイされます。その後結合テスト、\nシステムテストを行い、必要であれば承認後、本番環境にデプロイされます。")]),t._v(" "),s("h2",{attrs:{id:"_2-droneとは"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-droneとは"}},[t._v("#")]),t._v(" 2. droneとは")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone"),s("OutboundLink")],1),t._v(" とはdockerをベースとしたCI/CDのためのプラットフォームです。\nIIJ社内ではdrone v1.0を提供しています。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("社内のプライベートな環境で使えるdroneが用意されていることがあります。\n講師の指示がある場合はそちらの環境を利用しましょう。")])]),t._v(" "),s("ul",[s("li",[t._v("サイト: "),s("a",{attrs:{href:"https://cloud.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://cloud.drone.io/"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("ドキュメント: "),s("a",{attrs:{href:"https://docs.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://docs.drone.io/"),s("OutboundLink")],1)])]),t._v(" "),s("p",[t._v("GitHubと連携して簡単に設定を行うことができ、設定もyamlに記載するシンプルなもので、dockerベースのため環境構築も簡単に行うことができます。")]),t._v(" "),s("h3",{attrs:{id:"_2-1-とりあえず初めてみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-とりあえず初めてみる"}},[t._v("#")]),t._v(" 2.1. とりあえず初めてみる")]),t._v(" "),s("h4",{attrs:{id:"_2-1-1-droneの設定を有効化する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-1-droneの設定を有効化する"}},[t._v("#")]),t._v(" 2.1.1. droneの設定を有効化する")]),t._v(" "),s("p",[t._v("このハンズオンのためにCI/CDを行うためのサンプルリポジトリを "),s("a",{attrs:{href:"https://github.com/iij/drone-exercise",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/iij/drone-exercise"),s("OutboundLink")],1),t._v(" に用意しています。")]),t._v(" "),s("p",[t._v("💻 GitHub上で操作し、作業用リポジトリを作成してください。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(256),alt:"droneで最初のテスト"}})]),t._v(" "),s("p",[t._v("上記リポジトリを開いて「Use this template」を押してください。"),s("br"),t._v("\nリポジトリ名は「"),s("code",[t._v("drone-exercise-")]),t._v("」にしましょう。"),s("br"),t._v("\nほかの設定値はデフォルトで良いです。")]),t._v(" "),s("p",[t._v("ここで作成したリポジトリに対して操作をしていきます。")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("Use this template が表示されていない場合は正しくログインできているか確認してください。"),s("br"),t._v("\n講師から repository を作成する organization が指示されていれば、それに従ってください。")])]),t._v(" "),s("p",[t._v("droneはGitHub上のコミットやpushといったイベントが発生するとそれに応じて自動的に処理が走るようになっています。\nこれはWebhookというしくみを用いて実現されていますが、droneを使う前にこの設定が必要です。")]),t._v(" "),s("p",[t._v("💻 droneにリポジトリを登録する。")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://cloud.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://cloud.drone.io/"),s("OutboundLink")],1),t._v(" では 新規のユーザー登録を行っていません。"),s("br"),t._v("\nそのため、以下の手順を実施するためには "),s("a",{attrs:{href:"http://drone.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone.io"),s("OutboundLink")],1),t._v(" の 構築が必要です。"),s("br"),t._v("\n講師は接続先を案内してください。")])]),t._v(" "),s("p",[s("a",{attrs:{href:"http://xn--drone-f83dqcwesos420avc3aymzhv8g.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("講師に案内されたdrone.io"),s("OutboundLink")],1),t._v(" にログインしてください。")]),t._v(" "),s("p",[t._v("初回のログインでは OAuth の連携の許可が必要になるかもしれません。")]),t._v(" "),s("p",[t._v("Repositories の リストから「自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v("」を探してリポジトリ名をクリックし詳細ページを開きましょう。")]),t._v(" "),s("p",[t._v("見つからない場合は「SYNC」ボタンを押してから探してください。")]),t._v(" "),s("p",[t._v("「SETTINGS」タブから「ACTIVATE REPOSITORY」をクリックすると自動で設定が行われ、設定画面が表示されます。")]),t._v(" "),s("p",[t._v("これでdroneを利用する準備が整いました。")]),t._v(" "),s("h4",{attrs:{id:"_2-1-2-droneでテストを実行する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-2-droneでテストを実行する"}},[t._v("#")]),t._v(" 2.1.2. droneでテストを実行する")]),t._v(" "),s("p",[t._v("💻 作成した作業用リポジトリ(自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v(")をローカルにgit cloneしてください。")]),t._v(" "),s("p",[t._v("このリポジトリにはすでにdroneの設定ファイルが置かれています。\n適当に"),s("code",[t._v("README.md")]),t._v("を編集してコミット、pushしてみましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("おさらいです。 編集したあとは git add でステージング したのち commit && push となります。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('date >> README.md\ngit add README.md\ngit commit -m "update README.md"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])])]),t._v(" "),s("p",[t._v("GitHub に push してしばらくすると drone で テストが実行されます。")]),t._v(" "),s("p",[t._v("先程開いた droneの「自分のアカウント名/"),s("code",[t._v("drone-exercise-")]),t._v("」の 詳細ページから「ACTIVITY FEED」タブを開くとテストの実行ログが表示されます。")]),t._v(" "),s("p",[t._v("クリックして 実行ログを読むとどのようにテストが実行されているかが分かります。")]),t._v(" "),s("p",[t._v("このリポジトリにはRubyで書かれたプログラムと、Ruby用のテストフレームワークである"),s("a",{attrs:{href:"https://rspec.info/",target:"_blank",rel:"noopener noreferrer"}},[t._v("RSpec"),s("OutboundLink")],1),t._v("で\n書かれたテストが置かれています。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(279),alt:"droneで最初のテスト"}})]),t._v(" "),s("p",[t._v("図を見ると、 clone と test の step からなるとわかります。")]),t._v(" "),s("p",[t._v("それぞれクリックすると各 step の詳細が表示されます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント2 🏁")]),t._v(" "),s("p",[t._v("「test」ではどういうメッセージが出力されたでしょうか?")])]),t._v(" "),s("h4",{attrs:{id:"_2-1-3-webhookの設定確認"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-3-webhookの設定確認"}},[t._v("#")]),t._v(" 2.1.3 Webhookの設定確認")]),t._v(" "),s("p",[t._v("drone と GitHub の連携には Webhook を利用しています。")]),t._v(" "),s("p",[t._v("デフォルトでは"),s("code",[t._v("pr")]),t._v("と"),s("code",[t._v("push")]),t._v("の2つが登録されています。")]),t._v(" "),s("p",[s("code",[t._v("pr")]),t._v("を指定すると、Pull Requestをオープンしたとき、または既存のPRへpushしたときにテストが実行されます。\n"),s("code",[t._v("push")]),t._v(" を指定すると、"),s("code",[t._v("git push")]),t._v(" したときにテストが実行されます。")]),t._v(" "),s("p",[t._v("この設定は 「Settings」->「Hooks」->「Webhooks」-> droneのエントリ -> Edit で確認でき、")]),t._v(" "),s("p",[t._v("設定画面最下部の「Recent Deliveries」では実際に発行されたWebhookを確認 & 再送信できます。")]),t._v(" "),s("h2",{attrs:{id:"_3-droneの基本的な設定"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-droneの基本的な設定"}},[t._v("#")]),t._v(" 3. droneの基本的な設定")]),t._v(" "),s("p",[t._v("drone設定の基本は、どういった環境で、どのようなコマンドを実行するかということを記述することです。")]),t._v(" "),s("p",[t._v("設定はKubernetesライクな書き方になっていますので、Kubernetesの知識があれば読みやすいです。")]),t._v(" "),s("p",[t._v("droneはバージョンによって設定ファイルの書き方が異なりますので、\n既存のプロジェクトを編集するときは気を付けてください。")]),t._v(" "),s("p",[t._v("droneの設定はデフォルトでリポジトリの一番上の階層に"),s("code",[t._v(".drone.yml")]),t._v("という名前で置きます。")]),t._v(" "),s("p",[t._v("2.1.2 でcloneしたリポジトリの"),s("code",[t._v(".drone.yml")]),t._v("を見てみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle install\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" rspec\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br")])]),s("p",[t._v("各項目について解説していきます。")]),t._v(" "),s("h3",{attrs:{id:"_3-1-pipeline"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-pipeline"}},[t._v("#")]),t._v(" 3.1. Pipeline")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("p",[t._v("一連のテスト実行の流れを"),s("code",[t._v("Pipeline")]),t._v("と呼びます。")]),t._v(" "),s("p",[t._v("まずyamlの先頭で"),s("code",[t._v("kind: pipeline")]),t._v("と記載し、この下に書かれる設定値がPipelineのものであることを宣言します。\nただIIJの環境では"),s("code",[t._v("Pipeline")]),t._v("以外の設定は利用できませんのでこの"),s("code",[t._v("kind")]),t._v("と"),s("code",[t._v("name")]),t._v("は固定になります。")]),t._v(" "),s("p",[s("code",[t._v("Pipeline")]),t._v("は複数の"),s("code",[t._v("Step")]),t._v("で構成されます。")]),t._v(" "),s("h3",{attrs:{id:"_3-2-steps"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-steps"}},[t._v("#")]),t._v(" 3.2. Steps")]),t._v(" "),s("p",[t._v("ひとつのPipelineで複数のテスト("),s("code",[t._v("Step")]),t._v(")を実行できます。")]),t._v(" "),s("p",[t._v("各"),s("code",[t._v("Step")]),t._v("は別々のdockerコンテナで実行され、各テストは独立した環境でテストできます。")]),t._v(" "),s("p",[t._v("UI上では各"),s("code",[t._v("Step")]),t._v("ごとに結果が分けて表示され、"),s("code",[t._v("name")]),t._v("で名前を付けることができ、これはUI上に表示されます。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(280),alt:"Stepの表示"}})]),t._v(" "),s("p",[s("code",[t._v("image")]),t._v(" はテストに利用するdockerイメージを指定します。")]),t._v(" "),s("p",[s("code",[t._v("image: ruby")]),t._v(" と指定した場合はDocker Hubの"),s("a",{attrs:{href:"https://hub.docker.com/_/ruby",target:"_blank",rel:"noopener noreferrer"}},[t._v("Ruby Official Image"),s("OutboundLink")],1),t._v("が利用されます。\n素性のわからないイメージを利用することはやめましょう。")]),t._v(" "),s("p",[t._v("また、"),s("code",[t._v("image: ruby:3.1.2")]),t._v(" のようにタグを指定して、特定のバージョンを利用できるイメージもありますが意図せず更新される場合があります。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("プライベートなDockerイメージ置き場を自分で作成することもできます。")])]),t._v(" "),s("p",[s("code",[t._v("commands")]),t._v(" にはコンテナ内で実行するコマンドを記述します。")]),t._v(" "),s("p",[s("code",[t._v("bundle install")]),t._v(" ではテスト実行に必要なライブラリをインストールしていて、"),s("code",[t._v("rspec")]),t._v("でテストを実行しています。")]),t._v(" "),s("p",[t._v("各テストが成功したかどうかは各コマンドのExit Codeを見ていて、Code 0以外ではテストは中断され失敗となります。\nテストが失敗すると以下のような表示になります。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(281),alt:"テスト失敗時の表示"}})]),t._v(" "),s("h2",{attrs:{id:"_4-pull-requestと組み合わせる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-pull-requestと組み合わせる"}},[t._v("#")]),t._v(" 4. Pull Requestと組み合わせる")]),t._v(" "),s("p",[t._v("droneを設定した状態でPull Requestを作成するとどうなるでしょうか。")]),t._v(" "),s("p",[t._v("💻 意図的にテストが失敗するようにコードを修正し、Pull Requestを作成してみましょう。")]),t._v(" "),s("ol",[s("li",[t._v("まず、別の branch へ checkout します")])]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("git checkout -b feature/text-error\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("ol",{attrs:{start:"2"}},[s("li",[t._v("実装である"),s("code",[t._v("hello_world.rb")]),t._v("を以下のように書き換えてみます。")])]),t._v(" "),s("div",{staticClass:"language-diff line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-diff"}},[s("code",[s("span",{pre:!0,attrs:{class:"token unchanged"}},[s("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" def world\n")])]),s("span",{pre:!0,attrs:{class:"token deleted-sign deleted"}},[s("span",{pre:!0,attrs:{class:"token prefix deleted"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" 'Hello World'\n")])]),s("span",{pre:!0,attrs:{class:"token inserted-sign inserted"}},[s("span",{pre:!0,attrs:{class:"token prefix inserted"}},[t._v("+")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" 'Goodby World'\n")])]),s("span",{pre:!0,attrs:{class:"token unchanged"}},[s("span",{pre:!0,attrs:{class:"token prefix unchanged"}},[t._v(" ")]),s("span",{pre:!0,attrs:{class:"token line"}},[t._v(" end\n")])])])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br")])]),s("ol",{attrs:{start:"3"}},[s("li",[t._v("編集した内容を commit し push します。")])]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add hello_world.rb\ngit commit -m "goodby"\ngit push origin feature/text-error\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("💻 GitHub を開いてPull Requestを作成しましょう。")]),t._v(" "),s("p",[t._v("別のbranch に push した内容を develop branch などへ取り込んでもらうためのリクエストを Pull Request(PR) と呼びます。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(282),alt:"Pull Requestを作成しましょう"}})]),t._v(" "),s("p",[t._v("もし、作業リポジトリを fork して作成した場合 PR の送り先が fork 元 repository になっています。")]),t._v(" "),s("p",[t._v("その時は 自分のrepository に PR を送るように base repository (左側) の 表記を見直してください。")]),t._v(" "),s("p",[t._v("無事PRを作成できた場合 PRのページへ遷移します。")]),t._v(" "),s("p",[t._v("ページ下部にdroneのテスト結果が表示されています。")]),t._v(" "),s("p",[t._v("一目でテストが失敗していることがわかるでしょう。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(283),alt:"Pull Requestに表示されたdroneの結果"}})]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント3 🏁")]),t._v(" "),s("p",[t._v("Pull Request は作成できましたか?"),s("br"),t._v(" "),s("a",{attrs:{href:"http://drone.io",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone.io"),s("OutboundLink")],1),t._v(" は動作しましたか?"),s("br"),t._v("\nテストが失敗しましたか?")])]),t._v(" "),s("h3",{attrs:{id:"_4-1-テストが失敗したらマージできないようにしたい"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-テストが失敗したらマージできないようにしたい"}},[t._v("#")]),t._v(" 4.1. テストが失敗したらマージできないようにしたい")]),t._v(" "),s("p",[t._v("さて、 先程のPRではテストに失敗してしまいました。")]),t._v(" "),s("p",[t._v("この状態でもMergeボタンを押すことは可能ですが、普通は押されたくないはずです。\nこの挙動はGitHubの設定画面から変更できます。")]),t._v(" "),s("p",[t._v("💻 テストが通ったときだけマージできるように設定する")]),t._v(" "),s("ol",[s("li",[t._v("「Settings」->「Branches」->「Branch protection rules」->「Add rule」を押し、")]),t._v(" "),s("li",[t._v("「Branch name pattern」に「master」と記入し、")]),t._v(" "),s("li",[t._v("「Include administrators」にチェックを入れます。")]),t._v(" "),s("li",[t._v("「Require status checks to pass before merging」にチェックを入れて")]),t._v(" "),s("li",[t._v("「Status checks found in the last week for this repository」に出ている\n「continuous-integration/drone/pr」と\n「continuous-integration/drone/push」にチェックを入れます。")]),t._v(" "),s("li",[t._v("「Create」します。")])]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("もし、continuous-integration/drone/pr が見つからない場合"),s("br"),t._v("\n先ほど作成したPRによる drone のテストがうまく動いていないかもしれません。"),s("br"),t._v("\nfork した場合は PR の作成先を確認する必要があります。"),s("br"),t._v("\nPR の作成先が間違っているかもしれません。見直してください。")])]),t._v(" "),s("p",[s("img",{attrs:{src:e(284),alt:"Branch protection rules"}})]),t._v(" "),s("p",[t._v("先程作成したPull Requestのページに戻るとマージボタンが押せなくなっています。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(285),alt:"マージできない状態"}})]),t._v(" "),s("p",[t._v("これは複数人で開発するときには便利な機能です。")]),t._v(" "),s("p",[t._v("このあとmasterブランチを利用しますのでBranch protection rulesは削除しておきましょう。")]),t._v(" "),s("p",[t._v("💻 Branch protection rules の一覧ページで"),s("code",[t._v("master")]),t._v("と名前がついたルールの"),s("code",[t._v("delete")]),t._v("ボタンを押す")]),t._v(" "),s("p",[t._v("💻 この後項目のためにmasterブランチに戻っておきましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("$ git checkout master\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント4 🏁")]),t._v(" "),s("p",[t._v("マージボタンが押せなくなったのはなぜですか?")])]),t._v(" "),s("h2",{attrs:{id:"_5-さまざまなプラグイン"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-さまざまなプラグイン"}},[t._v("#")]),t._v(" 5. さまざまなプラグイン")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://plugins.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("droneには様々なプラグインが用意されています。"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("主に外部と連携する機能が用意されています。\n後述する利用のしかたからも分かるとおり plugin は 単なる docker コンテナであるため、自分で開発することもできます。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Plugins are just Docker containers which means you can write plugins in any programming language that runs inside a container. You can even create plugins using simple bash scripting.\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br")])]),s("blockquote",[s("p",[s("a",{attrs:{href:"https://docs.drone.io/plugins/overview/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://docs.drone.io/plugins/overview/"),s("OutboundLink")],1),t._v(" より引用")])]),t._v(" "),s("h3",{attrs:{id:"_5-1-キャッシュプラグイン"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-キャッシュプラグイン"}},[t._v("#")]),t._v(" 5.1. キャッシュプラグイン")]),t._v(" "),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("この項目はS3互換のオブジェクトストレージが必要です。\n講師は接続先を案内してください。")])]),t._v(" "),s("p",[t._v("これまでの例ではテストを実行するときに必要なライブラリを"),s("code",[t._v("bundle install")]),t._v("で事前にダウンロードしてから実行していました。\nしかし毎回ダウンロードしていたのではテスト実行に時間がかかりますし、ネットワークの無駄です。")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://plugins.drone.io/drone-plugins/drone-s3-cache/",target:"_blank",rel:"noopener noreferrer"}},[t._v("s3-cache"),s("OutboundLink")],1),t._v("プラグインを使うと特定のディレクトリを\n"),s("a",{attrs:{href:"https://aws.amazon.com/jp/s3/",target:"_blank",rel:"noopener noreferrer"}},[t._v("S3"),s("OutboundLink")],1),t._v("に保存し、テストのたびに復元してくれる機能を提供します。")]),t._v(" "),s("h4",{attrs:{id:"_5-1-1-ライブラリの保存場所を変更する"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-1-ライブラリの保存場所を変更する"}},[t._v("#")]),t._v(" 5.1.1. ライブラリの保存場所を変更する")]),t._v(" "),s("p",[t._v("パッケージマネージャーによってはリポジトリの中ではなく、システムの特別な場所に配置するものがあります。\ns3-cacheプラグインはリポジトリ内にあるファイルしかキャッシュできません。")]),t._v(" "),s("p",[t._v("nodejsのパッケージマネージャーであるnpmはデフォルトでリポジトリ直下にライブラリを配置しますが、\nRubyのパッケージマネージャーであるbundlerはシステム領域にライブラリを保存するため、\nそのままではキャッシュさせることができません。\nほとんどの場合、パッケージマネージャーのオプションで保存場所を変更できますので、\nRubyを例に設定してみましょう。")]),t._v(" "),s("p",[t._v("Rubyのパッケージマネージャーであるbundlerは"),s("code",[t._v("--path")]),t._v("オプションで保存場所を指定できます。")]),t._v(" "),s("p",[s("code",[t._v("drone.yaml")]),t._v(" で 実行している "),s("code",[t._v("bundle install")]),t._v(" にオプションを渡し 一般的によく使われる"),s("code",[t._v("vendor/bundle")]),t._v("に保存するように変更してください。")]),t._v(" "),s("p",[t._v("💻 パッケージの保存先を変更する")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" - name: test\n image: ruby:2.6.2\n commands:\n - bundle install --path vendor/bundle\n - bundle exec rspec\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br")])]),s("h4",{attrs:{id:"_5-1-2-ライブラリをキャッシュさせてみる"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-2-ライブラリをキャッシュさせてみる"}},[t._v("#")]),t._v(" 5.1.2. ライブラリをキャッシュさせてみる")]),t._v(" "),s("p",[t._v("さっそくキャッシュさせてみましょう。")]),t._v(" "),s("p",[t._v("このプラグインはキャッシュしたデータを戻す"),s("code",[t._v("restore")]),t._v("と、キャッシュを行う"),s("code",[t._v("rebuild")]),t._v("の機能があります。")]),t._v(" "),s("p",[s("code",[t._v(".drone.yml")]),t._v("を編集してキャッシュを組み込んでみましょう。\n"),s("code",[t._v("rebuild")]),t._v("ステップで"),s("code",[t._v("vendor/bundle")]),t._v("ディレクトリをキャッシュし、\n"),s("code",[t._v("restore")]),t._v("ステップでキャッシュされたものを戻します。")]),t._v(" "),s("p",[s("code",[t._v("test")]),t._v("Stepの前後に、"),s("code",[t._v("restore")]),t._v("と"),s("code",[t._v("rebuild")]),t._v("を追加します。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("以下の設定は各環境で用意された接続先へ値を変更してください。")]),t._v(" "),s("p",[t._v("<変数名>で書かれた場所を適切な値で置き換えてください。")])]),t._v(" "),s("p",[t._v("💻 パッケージをキャッシュするように変更する")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" restore\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" plugins/s3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("cache\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("settings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("pull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("endpoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("access_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("secret_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("restore")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("path vendor/bundle\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rspec\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" rebuild\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" plugins/s3"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("cache\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("settings")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("pull")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("endpoint")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("access_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("secret_key")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("rebuild")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mount")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" vendor/bundle\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br"),s("span",{staticClass:"line-number"},[t._v("13")]),s("br"),s("span",{staticClass:"line-number"},[t._v("14")]),s("br"),s("span",{staticClass:"line-number"},[t._v("15")]),s("br"),s("span",{staticClass:"line-number"},[t._v("16")]),s("br"),s("span",{staticClass:"line-number"},[t._v("17")]),s("br"),s("span",{staticClass:"line-number"},[t._v("18")]),s("br"),s("span",{staticClass:"line-number"},[t._v("19")]),s("br"),s("span",{staticClass:"line-number"},[t._v("20")]),s("br"),s("span",{staticClass:"line-number"},[t._v("21")]),s("br"),s("span",{staticClass:"line-number"},[t._v("22")]),s("br"),s("span",{staticClass:"line-number"},[t._v("23")]),s("br"),s("span",{staticClass:"line-number"},[t._v("24")]),s("br"),s("span",{staticClass:"line-number"},[t._v("25")]),s("br"),s("span",{staticClass:"line-number"},[t._v("26")]),s("br")])]),s("p",[t._v("💻 コミットして実行してみましょう。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add .drone.yml\ngit commit -m "Cache導入"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[t._v("droneのUI上で最新の実行ログを開いて見ましょう。\n"),s("code",[t._v("restore")]),t._v("と"),s("code",[t._v("rebuild")]),t._v("のステップが増えていることを確認してください。")]),t._v(" "),s("p",[t._v("1回目はキャッシュされてないので何も起きませんが、2回目からはキャッシュが使われるので実行が早くなります。\n1回目の実行時間を確認してから、以下のように2回目のテストを実行してみてください。")]),t._v(" "),s("p",[s("code",[t._v("--allow-empty")]),t._v(" はファイルを変更していなくてもコミットを作ることができるオプションです。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git commit --allow-empty -m "Cacheの効果を確認する"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br")])]),s("div",{staticClass:"custom-block warning"},[s("p",{staticClass:"custom-block-title"},[t._v("WARNING")]),t._v(" "),s("p",[t._v("このキャッシュを利用する操作は drone で完結しない処理です。"),s("br"),t._v("\nもしオブジェクトストレージ側にトラブルがあれば 処理が長時間に及ぶ可能性があります。")]),t._v(" "),s("p",[t._v("また、drone 上の ジョブの同時実行数には限りがある場合があります。"),s("br"),t._v("\n処理が長時間に渡る場合は drone 上のジョブ実行結果の確認画面から キャンセルができます")])]),t._v(" "),s("p",[t._v("💻 テスト実行が早くなっていることを確認しましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント5 🏁")]),t._v(" "),s("p",[t._v("テストが速くなったのはなぜですか?")])]),t._v(" "),s("h2",{attrs:{id:"_6-さまざまな応用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-さまざまな応用"}},[t._v("#")]),t._v(" 6. さまざまな応用")]),t._v(" "),s("h3",{attrs:{id:"_6-1-text-lintを使った日本語チェックの例"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-1-text-lintを使った日本語チェックの例"}},[t._v("#")]),t._v(" 6.1. Text Lintを使った日本語チェックの例")]),t._v(" "),s("p",[t._v("droneはプログラムにしか使えないものでしょうか。そうではありません。\ndroneは何でも動かすことができますから、テストをすることだけが仕事ではありません。")]),t._v(" "),s("p",[t._v("ここでは自然言語のチェックを行う "),s("a",{attrs:{href:"https://textlint.github.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("textlint"),s("OutboundLink")],1),t._v(" を使った例を紹介します。")]),t._v(" "),s("p",[t._v("💻 stepsに以下の項目を追加してみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" textlint\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" node\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" npm install textlint\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" npm install textlint"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rule"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("preset"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("ja"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("technical"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("writing\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" $(npm bin)/textlint "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("format pretty"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("error "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("preset ja"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("technical"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("writing README.md\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("textlintはnodejsで動作しますので、イメージにnodeを指定します。\ntextlintはフレームワークのみでこれ単体で動かすことはできません。どういったものをチェックするかというルールは別に定義しなければいけません。\nここでは日本語の技術文書を書くうえで必要ないくつかのルールをまとめた\n"),s("a",{attrs:{href:"https://github.com/textlint-ja/textlint-rule-preset-ja-technical-writing",target:"_blank",rel:"noopener noreferrer"}},[t._v("textlint-rule-preset-ja-technical-writing"),s("OutboundLink")],1),t._v("\nを利用します。試しに "),s("code",[t._v("README.md")]),t._v("をチェックしてみましょう。")]),t._v(" "),s("p",[t._v("💻 README.mdをTextlintでチェックする。")]),t._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('git add .drone.yml\ngit commit -m "textlintによるチェック"\ngit push origin master\n')])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br")])]),s("p",[s("img",{attrs:{src:e(286),alt:"textlintのエラー"}})]),t._v(" "),s("p",[t._v("このようにチェックする対象はプログラムに限りませんので、マニュアルなどのドキュメントのチェックなどにも活用できます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント6 🏁")]),t._v(" "),s("p",[t._v("droneが利用できる事例としてふさわしいものはどれですか?")])]),t._v(" "),s("h3",{attrs:{id:"_6-2-services"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-services"}},[t._v("#")]),t._v(" 6.2 Services")]),t._v(" "),s("p",[t._v("単純なスクリプトやライブラリのテストはこれだけでも十分にdroneでテストできます。")]),t._v(" "),s("p",[t._v("ではデータベース使ったテストはできるでしょうか。")]),t._v(" "),s("p",[t._v("データベースのテストをするならデータベースのプロセスが上がっている必要があります。"),s("br"),t._v("\nでも1つのコンテナでアプリケーションと一緒にデータベースも一緒に立ち上げたくないですよね。")]),t._v(" "),s("p",[t._v("そのために"),s("code",[t._v("Service")]),t._v("というしくみがあります。"),s("br"),t._v("\n同時に複数のコンテナを立ち上げて待機させておき、テスト中利用できます。")]),t._v(" "),s("p",[t._v("サンプルとしてRuby on Rails+MySQLで構成されたアプリケーションを用意しました。")]),t._v(" "),s("p",[t._v("💻 "),s("a",{attrs:{href:"https://github.com/iij/drone-exercise-rails",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/iij/drone-exercise-rails"),s("OutboundLink")],1),t._v(" から 作業用リポジトリを作成し、git cloneしてください。")]),t._v(" "),s("p",[s("img",{attrs:{src:e(256),alt:"rails テスト"}})]),t._v(" "),s("p",[t._v("上記リポジトリを開いて「Use this template」を押してください。")]),t._v(" "),s("p",[t._v("リポジトリ名は「"),s("code",[t._v("drone-exercise-rails-")]),t._v("」にしましょう。"),s("br"),t._v("\nほかの設定値はデフォルトで良いです。")]),t._v(" "),s("p",[t._v("ここで作成したリポジトリに対して操作をしていきます。")]),t._v(" "),s("p",[t._v("Ruby on RailsはWebアプリケーションを作るためのRuby製フレームワークです。\nデータの保存にMySQLなどのデータベースを利用できます。")]),t._v(" "),s("p",[t._v("標準的なWebアプリケーションではデータベースなどの外部サービスにデータを保存し、それを読み取って加工して表示するという動作が多く、\nテストするときもデータベースが動いている必要があります。")]),t._v(" "),s("p",[t._v("上記リポジトリにはテストを行うだけの "),s("code",[t._v(".drone.yml")]),t._v(" が含まれています。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pipeline\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" default\n\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("steps")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ruby"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("2.6.2\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("environment")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("RAILS_ENV")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("commands")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 実行に必要なライブラリをインストールする")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rails db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("reset "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テスト用のデータベース、テーブルを作成する")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" bundle exec rails test "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テストを実行する")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br"),s("span",{staticClass:"line-number"},[t._v("7")]),s("br"),s("span",{staticClass:"line-number"},[t._v("8")]),s("br"),s("span",{staticClass:"line-number"},[t._v("9")]),s("br"),s("span",{staticClass:"line-number"},[t._v("10")]),s("br"),s("span",{staticClass:"line-number"},[t._v("11")]),s("br"),s("span",{staticClass:"line-number"},[t._v("12")]),s("br")])]),s("p",[t._v("💻 まずはこの状態でテストを実行し、結果を見てみましょう。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("新しいrepository への drone の 有効のしかた"),s("br"),t._v("\n内容の変更を伴わないcommit をする方法を思い出してください。")])]),t._v(" "),s("p",[t._v("ちなみにテストは "),s("code",[t._v("test/models/user_test.rb")]),t._v(" に書いてあります。")]),t._v(" "),s("p",[t._v("この状態ではデータベースが動いていないのでテストが成功しません。")]),t._v(" "),s("p",[t._v("テストしている間横で何か動かしておきたいという場合には "),s("code",[t._v("Service")]),t._v(" を使います。\n今回はMySQLを使いますが、"),s("a",{attrs:{href:"https://hub.docker.com/_/mysql",target:"_blank",rel:"noopener noreferrer"}},[t._v("MySQLは公式でdockerイメージが提供されています"),s("OutboundLink")],1),t._v("のでこれを利用します。")]),t._v(" "),s("p",[t._v("💻 以下の項目を"),s("code",[t._v(".drone.yml")]),t._v("に追加してください。")]),t._v(" "),s("p",[t._v("kind, name, steps と同じ高さでよいです(services の左側にスペースはいりません)")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("services")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" db\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" mysql"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("8.0.16\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("command")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"--default-authentication-plugin=mysql_native_password"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# MySQL8.0のデフォルト認証方式にRailsが対応していないため変更")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("environment")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("MYSQL_ALLOW_EMPTY_PASSWORD")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'yes'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# テスト用にパスワードなしで接続できるようにする")]),t._v("\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[s("code",[t._v("name")]),t._v(" で名前をつけて "),s("code",[t._v("image")]),t._v(" で使用するdockerイメージを指定します。")]),t._v(" "),s("p",[t._v("Railsではデータベースの設定を"),s("code",[t._v("config/database.yml")]),t._v("から読み込みます。"),s("br"),t._v("\ndroneで設定したデータベースへ接続するための設定値を見てみましょう。")]),t._v(" "),s("div",{staticClass:"language-yaml line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("test")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("<<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token important"}},[t._v("*default")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("host")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" db\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3306")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("socket")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token null important"}},[t._v("null")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("database")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" drone"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("exercise"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rails_test\n")])]),t._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[t._v("1")]),s("br"),s("span",{staticClass:"line-number"},[t._v("2")]),s("br"),s("span",{staticClass:"line-number"},[t._v("3")]),s("br"),s("span",{staticClass:"line-number"},[t._v("4")]),s("br"),s("span",{staticClass:"line-number"},[t._v("5")]),s("br"),s("span",{staticClass:"line-number"},[t._v("6")]),s("br")])]),s("p",[t._v("このファイルで接続先MySQLサーバのホストを指定しているのですが、"),s("br"),t._v("\nここでは"),s("code",[t._v(".drone.yml")]),t._v("で指定した"),s("code",[t._v("db")]),t._v("がホスト名になっていて、この名前で接続できます。")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("チェックポイント7 🏁")]),t._v(" "),s("p",[t._v("テスト実行中にデータベースはどこで実行されているでしょうか?")])]),t._v(" "),s("h2",{attrs:{id:"_8-参考情報"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_8-参考情報"}},[t._v("#")]),t._v(" 8. 参考情報")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://docs.drone.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("drone Documentation"),s("OutboundLink")],1)])]),t._v(" "),s("h2",{attrs:{id:"続き"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#続き"}},[t._v("#")]),t._v(" 続き")]),t._v(" "),s("ul",[s("li",[s("RouterLink",{attrs:{to:"/cicd_infra/github_actions/"}},[t._v("GitHub Actions でCIテスト・デプロイを回す")])],1)])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/14.433600fc.js b/assets/js/14.2a54f6d5.js similarity index 99% rename from assets/js/14.433600fc.js rename to assets/js/14.2a54f6d5.js index c0effdf1..1f42ec6d 100644 --- a/assets/js/14.433600fc.js +++ b/assets/js/14.2a54f6d5.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{395:function(s,t,e){s.exports=e.p+"assets/img/components-of-kubernetes.51120ad2.svg"},396:function(s,t,e){s.exports=e.p+"assets/img/module_03_pods.ccc5ba54.svg"},397:function(s,t,e){s.exports=e.p+"assets/img/image_clusterip.8223e0b9.svg"},398:function(s,t,e){s.exports=e.p+"assets/img/image_nodeport.5357aa05.svg"},399:function(s,t,e){s.exports=e.p+"assets/img/image_loadbalancer.7df1efb3.svg"},525:function(s,t,e){"use strict";e.r(t);var a=e(10),n=Object(a.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("header-table"),s._v(" "),t("h1",{attrs:{id:"kubernetes-でアプリケーション開発"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#kubernetes-でアプリケーション開発"}},[s._v("#")]),s._v(" Kubernetes でアプリケーション開発")]),s._v(" "),t("h2",{attrs:{id:"_0-まえがき"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-まえがき"}},[s._v("#")]),s._v(" 0. まえがき")]),s._v(" "),t("h3",{attrs:{id:"_0-1-想定している受講者"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-想定している受講者"}},[s._v("#")]),s._v(" 0-1. 想定している受講者")]),s._v(" "),t("p",[s._v("本講義では以下の受講者を対象としています。")]),s._v(" "),t("ul",[t("li",[s._v("Kubernetesという名前は知っているがどんなものなのかは知らない")]),s._v(" "),t("li",[s._v("Kubernetes入門しようにも何から始めたらよいのかわからない")]),s._v(" "),t("li",[s._v("Kubernetesの仕組みがわからない")])]),s._v(" "),t("h3",{attrs:{id:"_0-2-前提知識"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-前提知識"}},[s._v("#")]),s._v(" 0-2. 前提知識")]),s._v(" "),t("p",[s._v("以下の点を知らないと講義についていけない可能性があります。")]),s._v(" "),t("ul",[t("li",[s._v("Linuxの基本的なコマンド")]),s._v(" "),t("li",[s._v("dockerの基礎")])]),s._v(" "),t("p",[s._v("加えて以下の点を知っていると講義をスムーズに聞けます。")]),s._v(" "),t("ul",[t("li",[s._v("YAMLファイルの読み方/書き方")]),s._v(" "),t("li",[s._v("コンテナアーキテクチャの基礎")])]),s._v(" "),t("h3",{attrs:{id:"_0-3-事前準備"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-事前準備"}},[s._v("#")]),s._v(" 0-3. 事前準備")]),s._v(" "),t("ul",[t("li",[s._v("docker / docker-compose のインストール")]),s._v(" "),t("li",[s._v("Kubernetes環境\n"),t("ul",[t("li",[s._v("環境構築に自信が無い人katacodaを使ってください\n"),t("ul",[t("li",[t("a",{attrs:{href:"https://www.katacoda.com/courses/kubernetes/playground",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://www.katacoda.com/courses/kubernetes/playground"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("strong",[t("strong",[s._v("外部リソースなのでコピペする際は気を付けてください")])])])])]),s._v(" "),t("li",[s._v("ローカルでkubernetesを動かしたい人はkindを以下の手順で構築してください")])])])]),s._v(" "),t("blockquote",[t("p",[s._v("kindを使ったkubernetes環境の構築")]),s._v(" "),t("p",[s._v("kindはkubernetes in dockerの略です。その名の通り、dockerを使ってkubernetes環境を構築します。\n("),t("a",{attrs:{href:"https://kind.sigs.k8s.io/docs/user/quick-start/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ドキュメント参照"),t("OutboundLink")],1),s._v(")")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-amd64")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# chmod +x ./kind")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("dockerホストからkindに対してコマンドを実行したいのでkubectlをdockerホストに入れます")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v('# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("試験的にクラスターを構築して正しくインストールされたか確認する")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind create cluster")]),s._v("\nCreating cluster "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n ✓ Ensuring "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("node")]),s._v(" image "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("kindest/node:v1.24.0"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" 🖼 \n ✓ Preparing nodes 📦 \n ✓ Writing configuration 📜 \n ✓ Starting control-plane 🕹️ \n ✓ Installing CNI 🔌 \n ✓ Installing StorageClass 💾 \nSet kubectl context to "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind-kind"')]),s._v("\nYou can now use your cluster with:\n\nkubectl cluster-info --context kind-kind\n\nHave a question, bug, or feature request? Let us know"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!")]),s._v(" https://kind.sigs.k8s.io/"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#community 🙂")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# docker ps")]),s._v("\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\nd76ca5889d8d kindest/node:v1.24.0 "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"/usr/local/bin/entr…"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("59")]),s._v(" seconds ago Up "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("49")]),s._v(" seconds "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("127.0")]),s._v(".0.1:35447-"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("6443")]),s._v("/tcp kind-control-plane\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl cluster-info --context kind-kind")]),s._v("\nKubernetes control plane is running at https://127.0.0.1:35447\nCoreDNS is running at https://127.0.0.1:35447/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy\n\nTo further debug and diagnose cluster problems, use "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'kubectl cluster-info dump'")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get node")]),s._v("\nNAME STATUS ROLES AGE VERSION\nkind-control-plane Ready control-plane 2m43s v1.24.0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br")])]),t("p",[s._v("確認出来たら削除")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind delete cluster")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("bootcamp用のクラスター環境を構築する")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# vim cluster.yml ")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("以下の内容を記載する")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Cluster\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kind.x"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("k8s.io/v1alpha4\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("nodes")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" control"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("plane\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e \n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br")])]),t("p",[s._v("クラスター構築")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind create cluster --config cluster.yml ")]),s._v("\nCreating cluster "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n ✓ Ensuring "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("node")]),s._v(" image "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("kindest/node:v1.24.0"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" 🖼 \n ✓ Preparing nodes 📦 📦 📦 📦 \n ✓ Writing configuration 📜 \n ✓ Starting control-plane 🕹️ \n ✓ Installing CNI 🔌 \n ✓ Installing StorageClass 💾 \n ✓ Joining worker nodes 🚜 \nSet kubectl context to "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind-kind"')]),s._v("\nYou can now use your cluster with:\n\nkubectl cluster-info --context kind-kind\n\nThanks "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" using kind"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!")]),s._v(" 😊\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl cluster-info --context kind-kind")]),s._v("\nKubernetes control plane is running at https://127.0.0.1:46863\nCoreDNS is running at https://127.0.0.1:46863/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy\n\nTo further debug and diagnose cluster problems, use "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'kubectl cluster-info dump'")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get node")]),s._v("\nNAME STATUS ROLES AGE VERSION\nkind-control-plane Ready control-plane 72s v1.24.0\nkind-worker Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 33s v1.24.0\nkind-worker2 Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 33s v1.24.0\nkind-worker3 Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 32s v1.24.0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br")])])]),s._v(" "),t("h2",{attrs:{id:"_1-kubernetesとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-kubernetesとは"}},[s._v("#")]),s._v(" 1. Kubernetesとは")]),s._v(" "),t("p",[s._v("Kubernetesは複数サーバで構成された基盤上でコンテナ群を一元管理するためツール「コンテナオーケストレーションツール」と呼ばれるものです。最近ではdockerを使ってコンテナ単位でアプリケーションを実装することが多くなりましたが、docker単体では複数台のdockerホスト上でコンテナ群を一元管理することができません。そのため複数ホストで構成される規模のプロダクションに耐えられるシステムをdocker単体で構築することは困難とされてきました。そこで複数のdockerホストに跨ってコンテナアプリケーションをデプロイ、スケーリング、ネットワーク管理機能などをするオーケストレーションツールが登場しました。")]),s._v(" "),t("p",[s._v("Kubernetesは元々Googleがアプリケーションデプロイに利用していたBorgと呼ばれるクラスターマネージャーをOSS化したもので、現在はLinux Foundation傘下にあるCNCF(Cloud Native Computing Foundation)が管理しています。ランクはGraduatedで成熟したCNCFプロジェクトとなっています。")]),s._v(" "),t("blockquote",[t("p",[s._v("【豆知識】")]),s._v(" "),t("p",[s._v("Kubernetesはギリシャ語で「操舵士」や「パイロット」を意味し、ロゴは操舵士にちなんで舵をモチーフにされています。7つのスポークは当初のKubernetesのコードネーム「Project Seven」にちなんでいます。")])]),s._v(" "),t("p",[s._v("KubernetesをベースにカスタマイズしたKubernetesサービスを最近ではKaaS(Kubernetes as a Service)と言い、AWSやGCPなどの各クラウドベンダで提供されています。")]),s._v(" "),t("ul",[t("li",[s._v("Amazon EKS")]),s._v(" "),t("li",[s._v("Google Kubernetes Engine(GKE)")]),s._v(" "),t("li",[s._v("Azure Kubernetes Service(AKS)")])]),s._v(" "),t("p",[s._v("先ほど「カスタマイズ」と言いましたが、Kubernetesはそれ単体で完成するものではなくログ基盤にfluentdとelasticsearchを使ったり、それぞれのクラウドサービスとの繋ぎこみなど提供元によって機能やスペックが異なります。このようにカスタマイズされたKubernetes基盤のことをLinuxのディストリビューションに例えて「Kubernetesディストリビューション」と呼びます。")]),s._v(" "),t("p",[s._v("IIJでも社内向けのKubernetes基盤としてIKE(IIJ Kubernetes Engine)の運用と導入が進んでいます。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://www.iij.ad.jp/dev/report/iir/040/03.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("IIR"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://eng-blog.iij.ad.jp/kubernetes",target:"_blank",rel:"noopener noreferrer"}},[s._v("IIJエンジニアブログ"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("従来のVMでのシステム構築と比べてKubernetesを利用することでシステム開発・管理が格段に楽になります。例えば従来のシステム構築では、どのVMに何を割り当てるかのリソース計算を人が考えなければならず、システムがスケーリングするたびに多くの労力を使いましたが、Kubernetesではマシンリソースやネットワークをプールとして扱い自動で管理するため、システムのスケーリングに柔軟に対応することができます("),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/scale/scale-intro/",target:"_blank",rel:"noopener noreferrer"}},[s._v("詳細"),t("OutboundLink")],1),s._v(")。また、従来ではシステムのアップデートを行うたびに「サービス停止→アップデート→サービス再開」という手順でアップデートをしていたが、Kubernetesではサービスを停止することなくシステムアップデートを行うことができ、サービス可用性を高めてくれます("),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/update/update-intro/",target:"_blank",rel:"noopener noreferrer"}},[s._v("詳細"),t("OutboundLink")],1),s._v(")。")]),s._v(" "),t("p",[s._v("上記以外にも多くのメリットがあり、Kubernetesでシステム開発を行うとアプリケーションの構築作業が劇的に減る他、APIなどからの自動デプロイなども非常に簡単に行うことができます。")]),s._v(" "),t("h2",{attrs:{id:"_2-kubernetesの基本構造"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-kubernetesの基本構造"}},[s._v("#")]),s._v(" 2. Kubernetesの基本構造")]),s._v(" "),t("h3",{attrs:{id:"_2-1-宣言的な構成管理"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-宣言的な構成管理"}},[s._v("#")]),s._v(" 2-1. 宣言的な構成管理")]),s._v(" "),t("p",[s._v("Kubernetes上にアプリケーションをデプロイする際、その構成管理は宣言的に行われます。デプロイしたい人は「アプリケーションやそれを構成するコンテナ群はこのような配置であるべき」という宣言(manifest)を"),t("strong",[s._v("マニフェストファイル")]),s._v("に記載することで、Kubernetesはマニフェストファイルに沿った構成を宣言どおりにデプロイします。このような構成管理方法はIaC(Infrastructure as a Code)と呼ばれており、Ansible同様に冪等性の確保や自動化に貢献しています。このような構成管理方法の主なメリットはGitによるバージョン管理のしやすさが挙げられます。")]),s._v(" "),t("blockquote",[t("p",[s._v("Ansibleで「Playbook」と呼ばれているものがKubernetesでいう「Manifest」です。")])]),s._v(" "),t("h3",{attrs:{id:"_2-2-コントロールプレーンとワーカーノード"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-コントロールプレーンとワーカーノード"}},[s._v("#")]),s._v(" 2-2. コントロールプレーンとワーカーノード")]),s._v(" "),t("p",[s._v("Kubernetesは大きく分けて2つの要素で構成されています。"),t("strong",[s._v("コントロールプレーン")]),s._v("と"),t("strong",[s._v("ワーカーノード")]),s._v("です。")]),s._v(" "),t("blockquote",[t("p",[s._v("文献によってはコントロールプレーンのことを"),t("strong",[s._v("マスターノード")]),s._v("と表記することがありますが、同じ意味なので誤解の無いように注意してください。")])]),s._v(" "),t("p",[t("img",{attrs:{src:e(395),alt:"component"}})]),s._v(" "),t("h4",{attrs:{id:"_2-2-1-コントロールプレーン"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-1-コントロールプレーン"}},[s._v("#")]),s._v(" 2-2-1. コントロールプレーン")]),s._v(" "),t("p",[s._v("コントロールプレーンはKubernetesクラスター全体の状態の管理を行うことが主な仕事です。例えばアプリケーション開発者が宣言したマニフェストファイルどおりに作られたPodがワーカーノードに割り当てられているかを監視し、割り当てられていなかった場合はそのPodを実行するノードを各のノードのリソース状況を考慮して割り当てます。このようなコンポーネントを"),t("strong",[s._v("kube-schduler")]),s._v("と言います。他にもマニフェストファイルによって宣言された構成情報を閲覧/編集するためのAPIサーバの役割を果たす"),t("strong",[s._v("kube-apiserver")]),s._v("などがあります。(他のコンポーネントも知りたい人は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/overview/components/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("へ)")]),s._v(" "),t("blockquote",[t("p",[s._v("【Podとは】")]),s._v(" "),t("p",[s._v("Kubernetesはコンテナを「pod」と呼ばれる単位で管理します。podにはいくつかのコンテナの集まりで、同じpodに所属するコンテナ同士はlocalhostでお互いに通信することができます。\n"),t("img",{attrs:{src:e(396),alt:"Pod"}}),s._v("\nPodにどのようなコンテナを同居させるのかは設計次第ですが、例えばアプリケーションのログを集めるコンテナを同じpodに同居させたり、nginxなどwebのフロントになるアプリケーションを同居させたりします。")])]),s._v(" "),t("h4",{attrs:{id:"_2-2-2-ワーカーノード"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-2-ワーカーノード"}},[s._v("#")]),s._v(" 2-2-2. ワーカーノード")]),s._v(" "),t("p",[s._v("ワーカーノードはPodの管理やPodの実行環境/通信機能を提供することが主な仕事です。例えばコントロールプレーンコンポーネントである"),t("strong",[s._v("kube-apiserver")]),s._v("から受け取った構成情報どおりにPodが稼働するように管理します。このようなコンポーネントを"),t("strong",[s._v("kubelet")]),s._v("と言います。ただしkubeletは実際にPodを作成したり、そのネットワーク環境を構築することはせず、あくまでもノード上のPod状態を維持するように管理することが仕事です。実際にPodを作ったりするコンポーネントを"),t("strong",[s._v("コンテナランタイム")]),s._v("と言います。他には、後程出てきますがService宛の通信を稼働中のPod群へ転送させる"),t("strong",[s._v("kube-proxy")]),s._v("などがあります。")]),s._v(" "),t("h3",{attrs:{id:"_2-3-kubernetesの基本構造まとめ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-kubernetesの基本構造まとめ"}},[s._v("#")]),s._v(" 2-3. Kubernetesの基本構造まとめ")]),s._v(" "),t("p",[s._v("Kubernetesは主に"),t("strong",[s._v("コントロールプレーン")]),s._v("と"),t("strong",[s._v("ワーカーノード")]),s._v("に分けられており、コントロールプレーンはクラスター全体の状態管理、ワーカーノードはコントロールプレーンからの指示通りにユーザによって宣言された構成を作り上げることが役割でした。そして、それぞれの役割を果たすために多くのコンポーネントが内蔵されている、という話でした。各コンポーネントについてもっと詳しく知りたい方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/architecture/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参照してください。")]),s._v(" "),t("h2",{attrs:{id:"_3-マニフェストファイルの書き方"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-マニフェストファイルの書き方"}},[s._v("#")]),s._v(" 3. マニフェストファイルの書き方")]),s._v(" "),t("h3",{attrs:{id:"_3-1-kubernetesオブジェクト"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-kubernetesオブジェクト"}},[s._v("#")]),s._v(" 3-1. Kubernetesオブジェクト")]),s._v(" "),t("p",[s._v("先ほども説明したように、Kubernetes上にPodなどをデプロイする際、ユーザはマニフェストファイルを書く必要があります。マニフェストファイルではいくつかのKubernetesオブジェクトを組み合わせて、ユーザの意図する状態を記載します。マニフェストファイルに記載されたKubernetesオブジェクトはコントロールプレーンによって読み取られ、読み取られたKubernetesオブジェクトが存在し続けるようにクラスター全体を管理します。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Kubernetesオブジェクト】")]),s._v(" "),t("p",[s._v("Kubernetesオブジェクトはクラスターの状態を表現するパーツです。以下にKubernetesオブジェクトの例と簡単な説明を記載します")]),s._v(" "),t("ul",[t("li",[s._v("ReplicaSet: Pod群の稼働状況を管理する")]),s._v(" "),t("li",[s._v("Deployment:バージョンに相当するReplicaSetを管理する")]),s._v(" "),t("li",[s._v("CronJob:定期実行するpodを管理する")]),s._v(" "),t("li",[s._v("Service:特定のラベルを持ち、サービスを提供できる状態のPod群への接続を提供する")]),s._v(" "),t("li",[s._v("Ingress:証明書やドメイン名を通して外部からの通信を制御する")]),s._v(" "),t("li",[s._v("PersistentVolume:ストレージなどの永続化volumeを管理する")])]),s._v(" "),t("p",[s._v("代表的な物を上げましたが、他にも色々あります。興味のある方は"),t("a",{attrs:{href:"https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式サイト"),t("OutboundLink")],1),s._v("参照。")])]),s._v(" "),t("h3",{attrs:{id:"_3-2-deployment"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-deployment"}},[s._v("#")]),s._v(" 3-2. Deployment")]),s._v(" "),t("p",[s._v("上でも述べた通りDeploymentはPodの稼働状況を管理するオブジェクトです。予め起動するPodの数を指定することで、何かしらの原因でPodが消失しても自動で立ち上げ直してくれたり、逆に多すぎる場合は終了させます。")]),s._v(" "),t("p",[s._v("現在稼働しているPodは、kubectlというcliツールを使って確認できます。\n今は何も稼働してないはずです。")]),s._v(" "),t("blockquote",[t("p",[s._v("【kubectl】")]),s._v(" "),t("p",[s._v("KubernetesのコントロールプレーンにはKubernetesクラスターの構成管理情報にアクセスするためのエンドポイントを提供する"),t("strong",[s._v("kube-apiserver")]),s._v("がありますが、生身の人間がAPIを生で叩いて"),t("strong",[s._v("kube-apiserver")]),s._v("にアクセスするのは少しキツイものがあります。そこでAPIをコマンドで操作できる"),t("strong",[s._v("kubectl")]),s._v("というものがあり、kubectlを使うことによりコマンドベースでAPIを叩くことができます。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl get pods\nNo resources found in default namespace.\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("以下のようなマニフェストファイルを"),t("code",[s._v("app.yml")]),s._v("として作成し、Kubernetesクラスターにデプロイしてみましょう。\n"),t("code",[s._v("image")]),s._v("として指定しているのはサンプル用の簡単なアプリケーションです。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Deployment\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("replicas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("app\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" registry.k8s.io/echoserver"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1.4")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("restartPolicy")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Always\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br")])]),t("blockquote",[t("p",[s._v("【Deploymentにおける必須フィールド】")]),s._v(" "),t("p",[s._v("Kubernetesオブジェクトをマニフェストファイルに記載する際、必ず以下のフィールドに値をセットする必要があります")]),s._v(" "),t("ul",[t("li",[s._v("apiVersion:オブジェクトのAPIVersionを指定")]),s._v(" "),t("li",[s._v("kind:どのオブジェクトを作るかを指定")]),s._v(" "),t("li",[s._v("metadata:オブジェクトを特定するための情報を指定")]),s._v(" "),t("li",[s._v("spec:オブジェクトの状態を指定")])])]),s._v(" "),t("p",[t("code",[s._v("apiVersion")]),s._v("にはオブジェクトのAPIVersionを書きます。\nオブジェクトAPIがどのAPIGROUPに属しているかでapiVersionの書き方が変わってきます。\n今回はDeploymentのオブジェクトなのでそのAPIグループを調べます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl api-resources\nNAME SHORTNAMES APIGROUP NAMESPACED KIND\nbindings true Binding\ncomponentstatuses cs false ComponentStatus\nconfigmaps cm true ConfigMap\n...\ndeployments deploy apps true Deployment\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br")])]),t("p",[s._v("ここではDeploymentが"),t("code",[s._v("apps")]),s._v("に属しているということが分かりました。\nもしAPIGROUPが空の場合はCore groupに属するため、"),t("code",[s._v("apiVersion: v1")]),s._v("で問題ないです。\n次にAPIGROUPで利用可能なversionを調べます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl api-versions | grep apps\napps/v1\napps/v1beta1\napps/v1beta2\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("ここでは3つほど出ましたが、この中の最も新しいversionを使ってください。\n今回は"),t("code",[s._v("apps/v1")]),s._v("を使ってマニフェストファイルを作りました。")]),s._v(" "),t("p",[s._v("yamlを作成したら、以下のコマンドでデプロイできます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl apply -f app.yml\ndeployment.apps/bootcamp created\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("別端末で"),t("code",[s._v("get pods")]),s._v("しながらpodが作られる様子を見てみましょう"),t("code",[s._v("-w")]),s._v("をつけると自動で表示を更新してくれます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl get pods -w\nNAME READY STATUS RESTARTS AGE\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 11s\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 11s\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 83s\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 84s\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br")])]),t("p",[t("code",[s._v("Running")]),s._v("となっていれば無事にアプリケーションが起動しました。今回は"),t("code",[s._v("replicas")]),s._v("に"),t("code",[s._v("2")]),s._v("を指定したのでpodが2個起動しています。"),t("code",[s._v("replicas")]),s._v("の値を変えて再度"),t("code",[s._v("kubectl apply")]),s._v("して遊んでみましょう。")]),s._v(" "),t("h3",{attrs:{id:"_3-3-service"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-service"}},[s._v("#")]),s._v(" 3-3. Service")]),s._v(" "),t("p",[s._v("Podの起動ができましたので、次はPodへのアクセスを試みます。KubernetesクラスターではPod群へのサービスディスカバリーの方法としてServiceオブジェクトが用いられます。Serviceを利用することでPod群に共通のIPアドレスを割り当て、まるで一つの「サービス」であるかのようにアクセスできるようになります。")]),s._v(" "),t("blockquote",[t("p",[s._v("【PodとServiceの関係】")]),s._v(" "),t("p",[s._v("Podは生成の度にIPアドレスが割り振られます。これは何かしらの理由でPodが落ちて別のPodが再生成されるときにもIPアドレスが割り振られますが、落ちたPodと同じIPアドレスが割り振られるとは限りません。こうなった場合に新しいPodへアクセスしたい別Podは新しいPodのIPアドレスがわからなくなってしまいます。ServiceはこのようなPodを共通のIPアドレスで管理し、Podへのアクセスやロードバランシングを行う役割を持っています。また、Serviceの生成によりKubernetesクラスター内の"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tasks/administer-cluster/coredns/",target:"_blank",rel:"noopener noreferrer"}},[s._v("CoreDNS"),t("OutboundLink")],1),s._v("のA/AAAAレコードやPod内の"),t("code",[s._v("resolve.conf")]),s._v("が自動的に書き換えられるため、Service名を使ってPodへアクセスすることも可能になります。")])]),s._v(" "),t("blockquote",[t("p",[s._v("【ServiceからPodへの通信の受け渡し】")]),s._v(" "),t("p",[s._v("Serviceが作られるとService宛の通信がPodへ転送されますが、その仕組みは"),t("strong",[s._v("ワーカーノード")]),s._v("内のコンポーネントである"),t("strong",[s._v("kube-proxy")]),s._v("によって実現されます。すべてのServiceは基本的にClusterIP(あとで説明します)によるVIPの保持が義務付けられており、またClusterIP配下のPodのIPアドレスはendpointに記載されています。そして、ClusterIPからPodの持つIPへの振り替えを"),t("strong",[s._v("kube-proxy")]),s._v("が行います。"),t("strong",[s._v("kube-proxy")]),s._v("の振り替え方式はいくつか選択肢がありますが、デフォルトの"),t("strong",[s._v("iptableモード")]),s._v("ではiptablesのchainがあり、これによってパケットが転送されます。他のモードについて知りたい方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参照してください。")])]),s._v(" "),t("p",[s._v("先ほどと同じようにServiceのマニフェストファイルを作りましょう。今回は"),t("code",[s._v("service.yml")]),s._v("とします。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("svc\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterIP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br")])]),t("p",[s._v("Serviceオブジェクトの中には様々なサービスタイプ種類があり、今回は"),t("code",[s._v("ClusterIP")]),s._v("というサービスタイプを利用しています。ClusterIPはServiceにおけるデフォルト設定であり、明示的に記載が無ければ"),t("code",[s._v("type: ClusterIP")]),s._v("が設定されることに注意してください。")]),s._v(" "),t("blockquote",[t("p",[s._v("【サービスタイプ】")]),s._v(" "),t("p",[s._v("それぞれのServiceの特徴について簡単に触れます。少し長くなるので講義では"),t("code",[s._v("ClusterIP")]),s._v("のみを説明しますが、興味のある人は他のサービスタイプも読んでみてください。")]),s._v(" "),t("h4",{attrs:{id:"clusterip"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#clusterip"}},[s._v("#")]),s._v(" ClusterIP")]),s._v(" "),t("p",[s._v("ClusterIPによって割り振られるIPアドレスはKubernetesクラスター内でのみ有効です。主にクラスター外からアクセスする必要のない箇所などでクラスター内ロードバランスをする際に利用されます。\n"),t("img",{attrs:{src:e(397),alt:"ClusterIP"}})]),s._v(" "),t("h4",{attrs:{id:"nodeport"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#nodeport"}},[s._v("#")]),s._v(" NodePort")]),s._v(" "),t("p",[s._v("ClusterIPを作った上で、全node各々の"),t("code",[s._v("")]),s._v("で受信したアクセスをServiceへ転送することで、クラスタ外からアクセスできるようにします。Docker Swarmでいうところの"),t("code",[s._v("Expose")]),s._v("です。図では全Kubernetes nodeの"),t("code",[s._v("port:30080")]),s._v("へのアクセスを"),t("code",[s._v("NodePort Service")]),s._v("に転送しています。\n"),t("img",{attrs:{src:e(398),alt:"NodePort"}})]),s._v(" "),t("h4",{attrs:{id:"loadbalancer"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#loadbalancer"}},[s._v("#")]),s._v(" LoadBalancer")]),s._v(" "),t("p",[s._v("Kubernetesクラスター外のロードバランサーより払い出された仮想IPアドレスを利用してクラスター外からのアクセスを可能にします。NodePortでは各nodeに"),t("code",[s._v(":")]),s._v("が割り振られ、ユーザはいずれかのアドレス宛にアクセスするため、アクセスしているnodeで障害が起きた際にそのnodeを利用しているユーザはサービスを利用できなくなります。それに対して"),t("code",[s._v("type: LoadBalancer")]),s._v("は、ユーザがクラスター外のロードバランサーから払い出されたIPアドレスのみを知っておくだけでサービスを利用することができます。また、nodeで障害が起きてもそのnodeの切り離しを行うようにクラスター外のロードバランサーを設定することで、ユーザはサービスを継続して利用することができます(ただし従来のロードバランサー+仮想マシンの組み合わせ同様に、障害検知から除外までの間は通信断が発生します)。ここでいうクラスター外のロードバランサーはプロバイダに依存しており、たとえばGCPの場合はGCLBが使われています。\n"),t("img",{attrs:{src:e(399),alt:"LoadBalancer"}})])]),s._v(" "),t("p",[s._v("それでは同じようにapplyしてから"),t("code",[s._v("Service")]),s._v("の稼働状況を確認します。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl apply -f service.yml\nservice/bootcamp-svc created\n$ kubectl get svc\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("S"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" AGE\nbootcamp-svc ClusterIP xxx.xxx.xxx.xxx "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v("/TCP 1h\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br")])]),t("p",[s._v("次に実際にPodにアクセスしてみましょう。"),t("code",[s._v("kubectl proxy")]),s._v("でコントロールプレーンのAPIサーバにポートフォワーディングします。先ほども説明しましたが"),t("code",[s._v("type: ClusterIP")]),s._v("は外から直接アクセスができません。そのため手元のホストからコントロールプレーンまでをポートフォワードし、コントロールプレーンからPodまでをREST APIを使って通信させます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl proxy\nStarting to serve on 127.0.0.1:8001\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("このプロキシ機能はServiceへのアクセスをRESTとして"),t("code",[s._v("/api/v1/namespaces//services/::/proxy/")]),s._v("と表現しているため、今回は"),t("code",[s._v("http://127.0.0.1:8001/api/v1/namespaces//services/bootcamp-svc/proxy/")]),s._v("へアクセスすることでコンテンツを取得することができます。")]),s._v(" "),t("blockquote",[t("p",[t("code",[s._v("")]),s._v("にはデプロイ先のnamespaceを入力します。\nnamespaceがわからない場合は"),t("code",[s._v("kubectl config get-contexts")]),s._v("から探してください。"),t("code",[s._v("CURRENT")]),s._v("に米印が付いているものがいま作業しているコンテキストになります。もし"),t("code",[s._v("NAMESPACE")]),s._v("の欄に何もなければ"),t("code",[s._v("namespace: default")]),s._v("ということになります。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl config get-contexts\nCURRENT NAME CLUSTER AUTHINFO NAMESPACE\n minikube minikube nirazuka\n* nira nirakube nirazuka nirazuka\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])])]),s._v(" "),t("p",[s._v("katacodeを使っている場合、RESTを辿ることができないため"),t("code",[s._v("kubectl port-foward")]),s._v("を利用します。"),t("code",[s._v("kubectl port-foward")]),s._v("はローカルのポートをPodやServiceに直接フォワーディングすることができます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl port-forward service/bootcamp-svc --address=0.0.0.0 :80\nForwarding from 0.0.0.0:35715 -> 8080\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("あとはTerminal横の「+」ボタンから「select port to view on Host 1」を選択し、表示されているポートへアクセスすればコンテンツを取得することができます。")]),s._v(" "),t("p",[t("code",[s._v("Hello Kubernetes!")]),s._v(" が表示されたでしょうか。無事にpodにアクセスすることができました。")]),s._v(" "),t("blockquote",[t("p",[s._v("今回はServiceでアプリケーションを公開しましたが、本来はServiceの上にIngressを作って公開することが推奨されています。\nIngressを利用するとSSLの設定やVirtualHostの設定などを行えるようになります。\n興味のある方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/services-networking/ingress/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参考に触ってみて下さい。")])]),s._v(" "),t("h3",{attrs:{id:"_3-4-podを削除してみる"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-podを削除してみる"}},[s._v("#")]),s._v(" 3-4. Podを削除してみる")]),s._v(" "),t("p",[s._v("試しに手動で無理やりpodを削除してみましょう。"),t("code",[s._v("kubectl get pods -w")]),s._v("で確認しながら、以下のコマンドでpodを削除してみます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl delete pods "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("pod-name"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("例によってpod-nameはコピペしてください。"),t("code",[s._v("kubectl get pods -w")]),s._v("しているとPodの数が"),t("code",[s._v("replicas")]),s._v("の設定値に合うように新しく起動される様子が分かります。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl get pods -w\nNAME READY STATUS RESTARTS AGE\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Terminating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Pending "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Pending "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 7s\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Terminating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br")])]),t("p",[t("code",[s._v("bootcamp-6bcddb7cf8-jpzg5")]),s._v("が手動で削除したpodです。"),t("code",[s._v("bootcamp-6bcddb7cf8-jpzg5")]),s._v("の削除が始まった途端に新しく"),t("code",[s._v("bootcamp-6bcddb7cf8-ffj7f")]),s._v("というpodを立てようとしているのが分かります。")]),s._v(" "),t("p",[s._v("このようにpodがエラーで停止したり、新しいアプリケーションのデプロイなどでpodを停止してもすぐさま"),t("code",[s._v("ReplicaSet")]),s._v("が状態を修復してくれます。\nそれだけではなく、前段の"),t("code",[s._v("Service")]),s._v("がpodの状態を監視しながら通信を流す先を決めてくれるため、一部のpodが停止している間も自動的に生きているpodに通信を流してくれます。")]),s._v(" "),t("p",[s._v("そのためユーザーに一切影響なくpodの停止と復旧が全て自動で可能になっています。このようなインフラをKubernetesとコンテナなしで構築するのはかなり困難です。")]),s._v(" "),t("h2",{attrs:{id:"_4-応用-kubernetesの監視"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-応用-kubernetesの監視"}},[s._v("#")]),s._v(" 4. 応用(Kubernetesの監視)")]),s._v(" "),t("p",[s._v("ここからは本格的なアプリケーションのデプロイを体験してもらいます。katacodeでやっている方はうまくいかないことがあるため本項目は飛ばしてください。")]),s._v(" "),t("p",[s._v("今回Kubernetes上に構築するアプリケーションは監視ツールのPrometheusで、以下の順序でデプロイします。(マニフェストファイルは"),t("a",{attrs:{href:"https://www.hanmoto.com/bd/isbn/9784910313009",target:"_blank",rel:"noopener noreferrer"}},[s._v("Prometheus実践ガイド"),t("OutboundLink")],1),s._v("の内容を一部改変したものを利用しています)")]),s._v(" "),t("ol",[t("li",[s._v("node exporterのデプロイ")]),s._v(" "),t("li",[s._v("RBAC認可を使ってリソースにアクセスするためのアカウントをデプロイ")]),s._v(" "),t("li",[s._v("Prometheusのデプロイ")])]),s._v(" "),t("h3",{attrs:{id:"_4-1-node-exporterのデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-node-exporterのデプロイ"}},[s._v("#")]),s._v(" 4-1. node exporterのデプロイ")]),s._v(" "),t("p",[s._v("node exporterは各ノードのメトリクス情報を収集するツール(exporter)です。これを各nodeに配置する必要がありますが、"),t("code",[s._v("Deployment")]),s._v("オブジェクトを利用すると配置nodeの指定を都度行う必要があり煩雑です。そのため、ここでは"),t("code",[s._v("DeamonSet")]),s._v("オブジェクトを利用します。"),t("code",[s._v("DeamonSet")]),s._v("オブジェクトは各ノードに等しくPodを配置するオブジェクトです。"),t("code",[s._v("node-exporter.yml")]),s._v("という名前で以下の内容のマニフェストファイルを作成します。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" DaemonSet\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'prom/node-exporter:v1.3.1'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("hostNetwork")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("hostPID")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("tolerations")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("key")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("role.kubernetes.io/control"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("plane\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("operator")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Exists\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("''")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("effect")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" NoSchedule\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br")])]),t("p",[s._v("各ノードに対して"),t("code",[s._v("prom/node-exporter:v1.3.1")]),s._v("というコンテナを1つずつデプロイさせています。"),t("code",[s._v("hostNetwork")]),s._v("と"),t("code",[s._v("hostPID")]),s._v("を"),t("code",[s._v("true")]),s._v("にすることでノードとコンテナのネットワーク/プロセスIDを共有させます。これは通常、コンテナはホストの環境とプロセス等が分離された状態になっているため、共有させないとPodからノードの情報を取得することができためです。"),t("code",[s._v("node-exporter")]),s._v("は外部から接続させる必要がないため、"),t("code",[s._v("Service")]),s._v("は"),t("code",[s._v("CluserIP")]),s._v("を指定しています。")]),s._v(" "),t("p",[s._v("準備が出来たら"),t("code",[s._v("kubectl apply -f node-exporter.yml")]),s._v("でデプロイします。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f node-exporter.yml")]),s._v("\ndaemonset.apps/node-exporter created\nservice/node-exporter created\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get pods")]),s._v("\nNAME READY STATUS RESTARTS AGE\nnode-exporter-75rpz "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\nnode-exporter-p25gq "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\nnode-exporter-tcbsp "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("h3",{attrs:{id:"_4-2-rbac認可を使ってリソースにアクセスするためのアカウントをデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-2-rbac認可を使ってリソースにアクセスするためのアカウントをデプロイ"}},[s._v("#")]),s._v(" 4-2. RBAC認可を使ってリソースにアクセスするためのアカウントをデプロイ")]),s._v(" "),t("p",[s._v("KubernetesはRole Based Access Control(RBAC)といわれる、各種リソースへのアクセス制御をユーザロールベースで行っています。そのため、監視に必要なリソースへのアクセスに必要な権限をユーザに付与する必要があります。ここでは権限の定義を行う"),t("code",[s._v("ClusterRole")]),s._v("、権限とユーザとの紐づけを行う"),t("code",[s._v("ClusterRoleBind")]),s._v("という二つのオブジェクトを利用します。"),t("code",[s._v("role-based-access-control.yml")]),s._v("という名前でマニフェストファイルを作り、以下の内容を記載します。")]),s._v(" "),t("div",{staticClass:"language-yaml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRole\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("rules")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroups")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("resources")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" nodes\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" services\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" endpoints\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" pods\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" metrics\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" nodes/metrics\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"list"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"watch"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroups")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" extensions\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("resources")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" ingresses\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"list"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"watch"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("nonResourceURLs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" /metrics\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRoleBinding\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("roleRef")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroup")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRole\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("subjects")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ServiceAccount\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ServiceAccount\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br")])]),t("p",[t("code",[s._v("default")]),s._v("namespace上の"),t("code",[s._v("prometheus")]),s._v("というアカウントに対して、各種リソースへの参照権限を付与する内容になります。"),t("code",[s._v("kubectl apply -f role-based-access-control.yml")]),s._v("を実行してデプロイします。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f role-based-access-control.yml ")]),s._v("\nclusterrole.rbac.authorization.k8s.io/prometheus created\nclusterrolebinding.rbac.authorization.k8s.io/prometheus created\nserviceaccount/prometheus created\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("これにより、API Serverなどへのアクセスするための認証情報が払い出されました。")]),s._v(" "),t("h3",{attrs:{id:"_4-3-prometheusのデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-prometheusのデプロイ"}},[s._v("#")]),s._v(" 4-3. Prometheusのデプロイ")]),s._v(" "),t("p",[s._v("最後にPrometheusのデプロイを行います。Prometheusのデプロイには"),t("code",[s._v("Deployment")]),s._v("と"),t("code",[s._v("Service")]),s._v("オブジェクトを利用しますが、Prometheus自体の設定ファイルは"),t("code",[s._v("ConfigMap")]),s._v("というオブジェクトを利用して定義します。これを利用することによりコンフィグファイルをマニフェストファイルとして管理することができ、さらにPrometheusに反映させることが出来ます。"),t("code",[s._v("prometheus.yml")]),s._v("というマニフェストファイルを作り以下の内容を記載します。")]),s._v(" "),t("div",{staticClass:"language-yaml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Deployment\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("replicas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("serviceAccountName")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prom/prometheus"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v2.33.3\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("imagePullPolicy")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" IfNotPresent\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("args")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("config.file=/prometheus/prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("log.level=debug\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("web.enable"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("lifecycle\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("volumeMounts")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("mountPath")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" /prometheus/prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("subPath")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("volumes")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("configMap")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterIP\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ConfigMap\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("data")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("prometheus.yml")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("|")]),t("span",{pre:!0,attrs:{class:"token scalar string"}},[s._v("\n global:\n scrape_interval: 15s\n scrape_configs:\n - job_name: 'prometheus'\n kubernetes_sd_configs:\n - role: pod\n relabel_configs:\n - source_labels: [__meta_kubernetes_pod_name]\n regex: prometheus-.+\n action: keep\n - job_name: 'apiserver'\n kubernetes_sd_configs:\n - role: service\n scheme: https\n tls_config:\n ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n authorization:\n credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token\n relabel_configs:\n - source_labels:\n - __meta_kubernetes_namespace\n - __meta_kubernetes_service_name\n - __meta_kubernetes_service_port_name\n action: keep\n regex: default;kubernetes;https\n - job_name: 'node-exporter'\n scheme: http\n kubernetes_sd_configs:\n - role: node\n relabel_configs:\n - source_labels: [__address__]\n action: replace\n regex: (.+):.+\n replacement: ${1}:9100\n target_label: __address__")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br"),t("span",{staticClass:"line-number"},[s._v("46")]),t("br"),t("span",{staticClass:"line-number"},[s._v("47")]),t("br"),t("span",{staticClass:"line-number"},[s._v("48")]),t("br"),t("span",{staticClass:"line-number"},[s._v("49")]),t("br"),t("span",{staticClass:"line-number"},[s._v("50")]),t("br"),t("span",{staticClass:"line-number"},[s._v("51")]),t("br"),t("span",{staticClass:"line-number"},[s._v("52")]),t("br"),t("span",{staticClass:"line-number"},[s._v("53")]),t("br"),t("span",{staticClass:"line-number"},[s._v("54")]),t("br"),t("span",{staticClass:"line-number"},[s._v("55")]),t("br"),t("span",{staticClass:"line-number"},[s._v("56")]),t("br"),t("span",{staticClass:"line-number"},[s._v("57")]),t("br"),t("span",{staticClass:"line-number"},[s._v("58")]),t("br"),t("span",{staticClass:"line-number"},[s._v("59")]),t("br"),t("span",{staticClass:"line-number"},[s._v("60")]),t("br"),t("span",{staticClass:"line-number"},[s._v("61")]),t("br"),t("span",{staticClass:"line-number"},[s._v("62")]),t("br"),t("span",{staticClass:"line-number"},[s._v("63")]),t("br"),t("span",{staticClass:"line-number"},[s._v("64")]),t("br"),t("span",{staticClass:"line-number"},[s._v("65")]),t("br"),t("span",{staticClass:"line-number"},[s._v("66")]),t("br"),t("span",{staticClass:"line-number"},[s._v("67")]),t("br"),t("span",{staticClass:"line-number"},[s._v("68")]),t("br"),t("span",{staticClass:"line-number"},[s._v("69")]),t("br"),t("span",{staticClass:"line-number"},[s._v("70")]),t("br"),t("span",{staticClass:"line-number"},[s._v("71")]),t("br"),t("span",{staticClass:"line-number"},[s._v("72")]),t("br"),t("span",{staticClass:"line-number"},[s._v("73")]),t("br"),t("span",{staticClass:"line-number"},[s._v("74")]),t("br"),t("span",{staticClass:"line-number"},[s._v("75")]),t("br"),t("span",{staticClass:"line-number"},[s._v("76")]),t("br"),t("span",{staticClass:"line-number"},[s._v("77")]),t("br"),t("span",{staticClass:"line-number"},[s._v("78")]),t("br"),t("span",{staticClass:"line-number"},[s._v("79")]),t("br"),t("span",{staticClass:"line-number"},[s._v("80")]),t("br"),t("span",{staticClass:"line-number"},[s._v("81")]),t("br"),t("span",{staticClass:"line-number"},[s._v("82")]),t("br"),t("span",{staticClass:"line-number"},[s._v("83")]),t("br"),t("span",{staticClass:"line-number"},[s._v("84")]),t("br"),t("span",{staticClass:"line-number"},[s._v("85")]),t("br"),t("span",{staticClass:"line-number"},[s._v("86")]),t("br"),t("span",{staticClass:"line-number"},[s._v("87")]),t("br"),t("span",{staticClass:"line-number"},[s._v("88")]),t("br"),t("span",{staticClass:"line-number"},[s._v("89")]),t("br"),t("span",{staticClass:"line-number"},[s._v("90")]),t("br"),t("span",{staticClass:"line-number"},[s._v("91")]),t("br"),t("span",{staticClass:"line-number"},[s._v("92")]),t("br"),t("span",{staticClass:"line-number"},[s._v("93")]),t("br"),t("span",{staticClass:"line-number"},[s._v("94")]),t("br"),t("span",{staticClass:"line-number"},[s._v("95")]),t("br"),t("span",{staticClass:"line-number"},[s._v("96")]),t("br"),t("span",{staticClass:"line-number"},[s._v("97")]),t("br"),t("span",{staticClass:"line-number"},[s._v("98")]),t("br"),t("span",{staticClass:"line-number"},[s._v("99")]),t("br")])]),t("p",[s._v("Prometheusの設定の詳細については割愛しますが、4-2ににて発行した認証情報は"),t("code",[s._v("tls_config")]),s._v("ならびに"),t("code",[s._v("authorization")]),s._v("で指定しています。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Prometheus講義受講者向け】")]),s._v(" "),t("p",[s._v("Prometheusの講義内で「Prometheusの特徴の1つにサービスディスカバリがあり、監視対象を動的に取得することができる」と話しました。\nそのサービスディスカバリは"),t("code",[s._v("kubernetes_sd_configs")]),s._v("の部分で設定しています。"),t("code",[s._v("role")]),s._v("という概念を利用してKubernetes内の各種リソースを動的に取得します。"),t("code",[s._v("role")]),s._v("で取得できるリソースは以下の5つです。")]),s._v(" "),t("ul",[t("li",[s._v("Node")]),s._v(" "),t("li",[s._v("Service")]),s._v(" "),t("li",[s._v("Endpoints")]),s._v(" "),t("li",[s._v("Pod")]),s._v(" "),t("li",[s._v("Ingress")])])]),s._v(" "),t("p",[t("code",[s._v("kubectl apply -f prometheus.yml")]),s._v("でPrometheusをデプロイし、確認を行います。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f prometheus.yml ")]),s._v("\nservice/prometheus created\ndeployment.apps/prometheus created\nconfigmap/prometheus created\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get all")]),s._v("\nNAME READY STATUS RESTARTS AGE\npod/node-exporter-75rpz "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/node-exporter-p25gq "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/node-exporter-tcbsp "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/prometheus-76b579c56c-r7nps "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("S"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" AGE\nservice/kubernetes ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".0.1 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("443")]),s._v("/TCP 29h\nservice/node-exporter ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".16.136 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("/TCP 115m\nservice/prometheus ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".128.27 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("/TCP 115m\n\nNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE\ndaemonset.apps/node-exporter "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 115m\n\nNAME READY UP-TO-DATE AVAILABLE AGE\ndeployment.apps/prometheus "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" 115m\n\nNAME DESIRED CURRENT READY AGE\nreplicaset.apps/prometheus-76b579c56c "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" 115m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br")])]),t("h3",{attrs:{id:"_4-4-prometheusの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-4-prometheusの確認"}},[s._v("#")]),s._v(" 4-4. Prometheusの確認")]),s._v(" "),t("p",[s._v("ひと通りのアプリケーションのデプロイが完了したので、さっそくアクセスします。Prometheusは"),t("code",[s._v("ClusterIP")]),s._v("の配下にあるため、ポートフォワーディングしてあげます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl port-forward svc/prometheus --address 0.0.0.0 8080:9090")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("ブラウザからアクセスし、"),t("code",[s._v("Status")]),s._v("タブの"),t("code",[s._v("Targets")]),s._v("を開いて全て問題なく取得できていれば完了です。\n"),t("img",{attrs:{src:"images/prometheus_main-menu.png",alt:"prometheus_main-nemu"}}),s._v("\nこれでKuberentes上の各コンポーネントに対して監視を行うことが出来ました。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Prometheus講義を受講した人向け】")]),s._v(" "),t("p",[s._v("式ブラウザから各種APIオブジェクトのメトリクス情報を取得してみてください。\nまた、Kubernetes上で動くアプリケーションの監視にはkube-state-metricsやcAdvidsorといったエクスポートを利用します。余裕のある人はPodの監視も行ってみてください。")])]),s._v(" "),t("h2",{attrs:{id:"_5-最後に"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-最後に"}},[s._v("#")]),s._v(" 5. 最後に")]),s._v(" "),t("p",[s._v("Kubernetesの紹介と代表的なオブジェクトである"),t("code",[s._v("Deployment")]),s._v("と"),t("code",[s._v("Service")]),s._v("について簡単に触ってみました。\nKubetenetesでは他にも様々なオブジェクトや設定を使います。")]),s._v(" "),t("p",[s._v("例えば")]),s._v(" "),t("ul",[t("li",[s._v("アプリケーションの環境変数を設定するために"),t("code",[s._v("env")]),s._v("を使う")]),s._v(" "),t("li",[s._v("データベースなどステートフルなpodを稼働させるために"),t("code",[s._v("StatefulSet")]),s._v("を使う")]),s._v(" "),t("li",[s._v("データの永続化のため"),t("code",[s._v("PersistentVolume")]),s._v("や"),t("code",[s._v("PersistentVolumeClaim")]),s._v("を使う")]),s._v(" "),t("li",[s._v("アプリケーションのコンフィグファイルを管理するのに"),t("code",[s._v("ConfigMap")]),s._v("を使う")]),s._v(" "),t("li",[s._v("APIキーやパスワードなど秘密情報を扱うために"),t("code",[s._v("Secret")]),s._v("を使う(ただしキー値はbase64でエンコードされた文字列)")])]),s._v(" "),t("p",[s._v("などなどです。"),t("code",[s._v("PersistentVolume")]),s._v("や"),t("code",[s._v("PersistentVolumeClaim")]),s._v("などはディストリビューションごとに扱い方が違ったりしますし、構築したいアプリケーションによってマニフェストファイルの書き方は様々なので今回は割愛しました。")]),s._v(" "),t("p",[s._v("社内でKubetenetesを使ってアプリケーションを構築する場合はIKEが使いやすいかと思いますので、ぜひチュートリアルなどを眺めてみてください。")]),s._v(" "),t("blockquote",[t("p",[s._v("【参考文献】")]),s._v(" "),t("ol",[t("li",[s._v("Kubernetes完全ガイド/青山信也(インプレス)")]),s._v(" "),t("li",[s._v("イラストでわかるDockerとKubernetes/徳永航平(技術評論社)")]),s._v(" "),t("li",[s._v("Docker/Kubernetes実践コンテナ開発入門/山田明憲(技術評論社)")]),s._v(" "),t("li",[t("a",{attrs:{href:"https://kubernetes.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Kubernetes公式ドキュメント"),t("OutboundLink")],1),s._v("/CNCF")]),s._v(" "),t("li",[s._v("Prometheus実践ガイド/仲亀拓馬(テッキーメディア)")])])])],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{392:function(s,t,e){s.exports=e.p+"assets/img/components-of-kubernetes.51120ad2.svg"},393:function(s,t,e){s.exports=e.p+"assets/img/module_03_pods.ccc5ba54.svg"},394:function(s,t,e){s.exports=e.p+"assets/img/image_clusterip.8223e0b9.svg"},395:function(s,t,e){s.exports=e.p+"assets/img/image_nodeport.5357aa05.svg"},396:function(s,t,e){s.exports=e.p+"assets/img/image_loadbalancer.7df1efb3.svg"},523:function(s,t,e){"use strict";e.r(t);var a=e(10),n=Object(a.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("header-table"),s._v(" "),t("h1",{attrs:{id:"kubernetes-でアプリケーション開発"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#kubernetes-でアプリケーション開発"}},[s._v("#")]),s._v(" Kubernetes でアプリケーション開発")]),s._v(" "),t("h2",{attrs:{id:"_0-まえがき"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-まえがき"}},[s._v("#")]),s._v(" 0. まえがき")]),s._v(" "),t("h3",{attrs:{id:"_0-1-想定している受講者"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-1-想定している受講者"}},[s._v("#")]),s._v(" 0-1. 想定している受講者")]),s._v(" "),t("p",[s._v("本講義では以下の受講者を対象としています。")]),s._v(" "),t("ul",[t("li",[s._v("Kubernetesという名前は知っているがどんなものなのかは知らない")]),s._v(" "),t("li",[s._v("Kubernetes入門しようにも何から始めたらよいのかわからない")]),s._v(" "),t("li",[s._v("Kubernetesの仕組みがわからない")])]),s._v(" "),t("h3",{attrs:{id:"_0-2-前提知識"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-2-前提知識"}},[s._v("#")]),s._v(" 0-2. 前提知識")]),s._v(" "),t("p",[s._v("以下の点を知らないと講義についていけない可能性があります。")]),s._v(" "),t("ul",[t("li",[s._v("Linuxの基本的なコマンド")]),s._v(" "),t("li",[s._v("dockerの基礎")])]),s._v(" "),t("p",[s._v("加えて以下の点を知っていると講義をスムーズに聞けます。")]),s._v(" "),t("ul",[t("li",[s._v("YAMLファイルの読み方/書き方")]),s._v(" "),t("li",[s._v("コンテナアーキテクチャの基礎")])]),s._v(" "),t("h3",{attrs:{id:"_0-3-事前準備"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_0-3-事前準備"}},[s._v("#")]),s._v(" 0-3. 事前準備")]),s._v(" "),t("ul",[t("li",[s._v("docker / docker-compose のインストール")]),s._v(" "),t("li",[s._v("Kubernetes環境\n"),t("ul",[t("li",[s._v("環境構築に自信が無い人katacodaを使ってください\n"),t("ul",[t("li",[t("a",{attrs:{href:"https://www.katacoda.com/courses/kubernetes/playground",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://www.katacoda.com/courses/kubernetes/playground"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("strong",[t("strong",[s._v("外部リソースなのでコピペする際は気を付けてください")])])])])]),s._v(" "),t("li",[s._v("ローカルでkubernetesを動かしたい人はkindを以下の手順で構築してください")])])])]),s._v(" "),t("blockquote",[t("p",[s._v("kindを使ったkubernetes環境の構築")]),s._v(" "),t("p",[s._v("kindはkubernetes in dockerの略です。その名の通り、dockerを使ってkubernetes環境を構築します。\n("),t("a",{attrs:{href:"https://kind.sigs.k8s.io/docs/user/quick-start/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ドキュメント参照"),t("OutboundLink")],1),s._v(")")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-amd64")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# chmod +x ./kind")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("dockerホストからkindに対してコマンドを実行したいのでkubectlをdockerホストに入れます")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v('# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("試験的にクラスターを構築して正しくインストールされたか確認する")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind create cluster")]),s._v("\nCreating cluster "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n ✓ Ensuring "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("node")]),s._v(" image "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("kindest/node:v1.24.0"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" 🖼 \n ✓ Preparing nodes 📦 \n ✓ Writing configuration 📜 \n ✓ Starting control-plane 🕹️ \n ✓ Installing CNI 🔌 \n ✓ Installing StorageClass 💾 \nSet kubectl context to "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind-kind"')]),s._v("\nYou can now use your cluster with:\n\nkubectl cluster-info --context kind-kind\n\nHave a question, bug, or feature request? Let us know"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!")]),s._v(" https://kind.sigs.k8s.io/"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#community 🙂")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# docker ps")]),s._v("\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\nd76ca5889d8d kindest/node:v1.24.0 "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"/usr/local/bin/entr…"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("59")]),s._v(" seconds ago Up "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("49")]),s._v(" seconds "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("127.0")]),s._v(".0.1:35447-"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("6443")]),s._v("/tcp kind-control-plane\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl cluster-info --context kind-kind")]),s._v("\nKubernetes control plane is running at https://127.0.0.1:35447\nCoreDNS is running at https://127.0.0.1:35447/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy\n\nTo further debug and diagnose cluster problems, use "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'kubectl cluster-info dump'")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get node")]),s._v("\nNAME STATUS ROLES AGE VERSION\nkind-control-plane Ready control-plane 2m43s v1.24.0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br")])]),t("p",[s._v("確認出来たら削除")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind delete cluster")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("bootcamp用のクラスター環境を構築する")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# vim cluster.yml ")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("以下の内容を記載する")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Cluster\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kind.x"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("k8s.io/v1alpha4\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("nodes")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" control"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("plane\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e \n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("role")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" worker\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" kindest/node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v1.24.0@sha256"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br")])]),t("p",[s._v("クラスター構築")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kind create cluster --config cluster.yml ")]),s._v("\nCreating cluster "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind"')]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n ✓ Ensuring "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("node")]),s._v(" image "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("kindest/node:v1.24.0"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" 🖼 \n ✓ Preparing nodes 📦 📦 📦 📦 \n ✓ Writing configuration 📜 \n ✓ Starting control-plane 🕹️ \n ✓ Installing CNI 🔌 \n ✓ Installing StorageClass 💾 \n ✓ Joining worker nodes 🚜 \nSet kubectl context to "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"kind-kind"')]),s._v("\nYou can now use your cluster with:\n\nkubectl cluster-info --context kind-kind\n\nThanks "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" using kind"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!")]),s._v(" 😊\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl cluster-info --context kind-kind")]),s._v("\nKubernetes control plane is running at https://127.0.0.1:46863\nCoreDNS is running at https://127.0.0.1:46863/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy\n\nTo further debug and diagnose cluster problems, use "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'kubectl cluster-info dump'")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get node")]),s._v("\nNAME STATUS ROLES AGE VERSION\nkind-control-plane Ready control-plane 72s v1.24.0\nkind-worker Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 33s v1.24.0\nkind-worker2 Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 33s v1.24.0\nkind-worker3 Ready "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 32s v1.24.0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br")])])]),s._v(" "),t("h2",{attrs:{id:"_1-kubernetesとは"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-kubernetesとは"}},[s._v("#")]),s._v(" 1. Kubernetesとは")]),s._v(" "),t("p",[s._v("Kubernetesは複数サーバで構成された基盤上でコンテナ群を一元管理するためツール「コンテナオーケストレーションツール」と呼ばれるものです。最近ではdockerを使ってコンテナ単位でアプリケーションを実装することが多くなりましたが、docker単体では複数台のdockerホスト上でコンテナ群を一元管理することができません。そのため複数ホストで構成される規模のプロダクションに耐えられるシステムをdocker単体で構築することは困難とされてきました。そこで複数のdockerホストに跨ってコンテナアプリケーションをデプロイ、スケーリング、ネットワーク管理機能などをするオーケストレーションツールが登場しました。")]),s._v(" "),t("p",[s._v("Kubernetesは元々Googleがアプリケーションデプロイに利用していたBorgと呼ばれるクラスターマネージャーをOSS化したもので、現在はLinux Foundation傘下にあるCNCF(Cloud Native Computing Foundation)が管理しています。ランクはGraduatedで成熟したCNCFプロジェクトとなっています。")]),s._v(" "),t("blockquote",[t("p",[s._v("【豆知識】")]),s._v(" "),t("p",[s._v("Kubernetesはギリシャ語で「操舵士」や「パイロット」を意味し、ロゴは操舵士にちなんで舵をモチーフにされています。7つのスポークは当初のKubernetesのコードネーム「Project Seven」にちなんでいます。")])]),s._v(" "),t("p",[s._v("KubernetesをベースにカスタマイズしたKubernetesサービスを最近ではKaaS(Kubernetes as a Service)と言い、AWSやGCPなどの各クラウドベンダで提供されています。")]),s._v(" "),t("ul",[t("li",[s._v("Amazon EKS")]),s._v(" "),t("li",[s._v("Google Kubernetes Engine(GKE)")]),s._v(" "),t("li",[s._v("Azure Kubernetes Service(AKS)")])]),s._v(" "),t("p",[s._v("先ほど「カスタマイズ」と言いましたが、Kubernetesはそれ単体で完成するものではなくログ基盤にfluentdとelasticsearchを使ったり、それぞれのクラウドサービスとの繋ぎこみなど提供元によって機能やスペックが異なります。このようにカスタマイズされたKubernetes基盤のことをLinuxのディストリビューションに例えて「Kubernetesディストリビューション」と呼びます。")]),s._v(" "),t("p",[s._v("IIJでも社内向けのKubernetes基盤としてIKE(IIJ Kubernetes Engine)の運用と導入が進んでいます。")]),s._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://www.iij.ad.jp/dev/report/iir/040/03.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("IIR"),t("OutboundLink")],1)]),s._v(" "),t("li",[t("a",{attrs:{href:"https://eng-blog.iij.ad.jp/kubernetes",target:"_blank",rel:"noopener noreferrer"}},[s._v("IIJエンジニアブログ"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("従来のVMでのシステム構築と比べてKubernetesを利用することでシステム開発・管理が格段に楽になります。例えば従来のシステム構築では、どのVMに何を割り当てるかのリソース計算を人が考えなければならず、システムがスケーリングするたびに多くの労力を使いましたが、Kubernetesではマシンリソースやネットワークをプールとして扱い自動で管理するため、システムのスケーリングに柔軟に対応することができます("),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/scale/scale-intro/",target:"_blank",rel:"noopener noreferrer"}},[s._v("詳細"),t("OutboundLink")],1),s._v(")。また、従来ではシステムのアップデートを行うたびに「サービス停止→アップデート→サービス再開」という手順でアップデートをしていたが、Kubernetesではサービスを停止することなくシステムアップデートを行うことができ、サービス可用性を高めてくれます("),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tutorials/kubernetes-basics/update/update-intro/",target:"_blank",rel:"noopener noreferrer"}},[s._v("詳細"),t("OutboundLink")],1),s._v(")。")]),s._v(" "),t("p",[s._v("上記以外にも多くのメリットがあり、Kubernetesでシステム開発を行うとアプリケーションの構築作業が劇的に減る他、APIなどからの自動デプロイなども非常に簡単に行うことができます。")]),s._v(" "),t("h2",{attrs:{id:"_2-kubernetesの基本構造"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-kubernetesの基本構造"}},[s._v("#")]),s._v(" 2. Kubernetesの基本構造")]),s._v(" "),t("h3",{attrs:{id:"_2-1-宣言的な構成管理"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-宣言的な構成管理"}},[s._v("#")]),s._v(" 2-1. 宣言的な構成管理")]),s._v(" "),t("p",[s._v("Kubernetes上にアプリケーションをデプロイする際、その構成管理は宣言的に行われます。デプロイしたい人は「アプリケーションやそれを構成するコンテナ群はこのような配置であるべき」という宣言(manifest)を"),t("strong",[s._v("マニフェストファイル")]),s._v("に記載することで、Kubernetesはマニフェストファイルに沿った構成を宣言どおりにデプロイします。このような構成管理方法はIaC(Infrastructure as a Code)と呼ばれており、Ansible同様に冪等性の確保や自動化に貢献しています。このような構成管理方法の主なメリットはGitによるバージョン管理のしやすさが挙げられます。")]),s._v(" "),t("blockquote",[t("p",[s._v("Ansibleで「Playbook」と呼ばれているものがKubernetesでいう「Manifest」です。")])]),s._v(" "),t("h3",{attrs:{id:"_2-2-コントロールプレーンとワーカーノード"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-コントロールプレーンとワーカーノード"}},[s._v("#")]),s._v(" 2-2. コントロールプレーンとワーカーノード")]),s._v(" "),t("p",[s._v("Kubernetesは大きく分けて2つの要素で構成されています。"),t("strong",[s._v("コントロールプレーン")]),s._v("と"),t("strong",[s._v("ワーカーノード")]),s._v("です。")]),s._v(" "),t("blockquote",[t("p",[s._v("文献によってはコントロールプレーンのことを"),t("strong",[s._v("マスターノード")]),s._v("と表記することがありますが、同じ意味なので誤解の無いように注意してください。")])]),s._v(" "),t("p",[t("img",{attrs:{src:e(392),alt:"component"}})]),s._v(" "),t("h4",{attrs:{id:"_2-2-1-コントロールプレーン"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-1-コントロールプレーン"}},[s._v("#")]),s._v(" 2-2-1. コントロールプレーン")]),s._v(" "),t("p",[s._v("コントロールプレーンはKubernetesクラスター全体の状態の管理を行うことが主な仕事です。例えばアプリケーション開発者が宣言したマニフェストファイルどおりに作られたPodがワーカーノードに割り当てられているかを監視し、割り当てられていなかった場合はそのPodを実行するノードを各のノードのリソース状況を考慮して割り当てます。このようなコンポーネントを"),t("strong",[s._v("kube-schduler")]),s._v("と言います。他にもマニフェストファイルによって宣言された構成情報を閲覧/編集するためのAPIサーバの役割を果たす"),t("strong",[s._v("kube-apiserver")]),s._v("などがあります。(他のコンポーネントも知りたい人は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/overview/components/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("へ)")]),s._v(" "),t("blockquote",[t("p",[s._v("【Podとは】")]),s._v(" "),t("p",[s._v("Kubernetesはコンテナを「pod」と呼ばれる単位で管理します。podにはいくつかのコンテナの集まりで、同じpodに所属するコンテナ同士はlocalhostでお互いに通信することができます。\n"),t("img",{attrs:{src:e(393),alt:"Pod"}}),s._v("\nPodにどのようなコンテナを同居させるのかは設計次第ですが、例えばアプリケーションのログを集めるコンテナを同じpodに同居させたり、nginxなどwebのフロントになるアプリケーションを同居させたりします。")])]),s._v(" "),t("h4",{attrs:{id:"_2-2-2-ワーカーノード"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-2-ワーカーノード"}},[s._v("#")]),s._v(" 2-2-2. ワーカーノード")]),s._v(" "),t("p",[s._v("ワーカーノードはPodの管理やPodの実行環境/通信機能を提供することが主な仕事です。例えばコントロールプレーンコンポーネントである"),t("strong",[s._v("kube-apiserver")]),s._v("から受け取った構成情報どおりにPodが稼働するように管理します。このようなコンポーネントを"),t("strong",[s._v("kubelet")]),s._v("と言います。ただしkubeletは実際にPodを作成したり、そのネットワーク環境を構築することはせず、あくまでもノード上のPod状態を維持するように管理することが仕事です。実際にPodを作ったりするコンポーネントを"),t("strong",[s._v("コンテナランタイム")]),s._v("と言います。他には、後程出てきますがService宛の通信を稼働中のPod群へ転送させる"),t("strong",[s._v("kube-proxy")]),s._v("などがあります。")]),s._v(" "),t("h3",{attrs:{id:"_2-3-kubernetesの基本構造まとめ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-kubernetesの基本構造まとめ"}},[s._v("#")]),s._v(" 2-3. Kubernetesの基本構造まとめ")]),s._v(" "),t("p",[s._v("Kubernetesは主に"),t("strong",[s._v("コントロールプレーン")]),s._v("と"),t("strong",[s._v("ワーカーノード")]),s._v("に分けられており、コントロールプレーンはクラスター全体の状態管理、ワーカーノードはコントロールプレーンからの指示通りにユーザによって宣言された構成を作り上げることが役割でした。そして、それぞれの役割を果たすために多くのコンポーネントが内蔵されている、という話でした。各コンポーネントについてもっと詳しく知りたい方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/architecture/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参照してください。")]),s._v(" "),t("h2",{attrs:{id:"_3-マニフェストファイルの書き方"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-マニフェストファイルの書き方"}},[s._v("#")]),s._v(" 3. マニフェストファイルの書き方")]),s._v(" "),t("h3",{attrs:{id:"_3-1-kubernetesオブジェクト"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-kubernetesオブジェクト"}},[s._v("#")]),s._v(" 3-1. Kubernetesオブジェクト")]),s._v(" "),t("p",[s._v("先ほども説明したように、Kubernetes上にPodなどをデプロイする際、ユーザはマニフェストファイルを書く必要があります。マニフェストファイルではいくつかのKubernetesオブジェクトを組み合わせて、ユーザの意図する状態を記載します。マニフェストファイルに記載されたKubernetesオブジェクトはコントロールプレーンによって読み取られ、読み取られたKubernetesオブジェクトが存在し続けるようにクラスター全体を管理します。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Kubernetesオブジェクト】")]),s._v(" "),t("p",[s._v("Kubernetesオブジェクトはクラスターの状態を表現するパーツです。以下にKubernetesオブジェクトの例と簡単な説明を記載します")]),s._v(" "),t("ul",[t("li",[s._v("ReplicaSet: Pod群の稼働状況を管理する")]),s._v(" "),t("li",[s._v("Deployment:バージョンに相当するReplicaSetを管理する")]),s._v(" "),t("li",[s._v("CronJob:定期実行するpodを管理する")]),s._v(" "),t("li",[s._v("Service:特定のラベルを持ち、サービスを提供できる状態のPod群への接続を提供する")]),s._v(" "),t("li",[s._v("Ingress:証明書やドメイン名を通して外部からの通信を制御する")]),s._v(" "),t("li",[s._v("PersistentVolume:ストレージなどの永続化volumeを管理する")])]),s._v(" "),t("p",[s._v("代表的な物を上げましたが、他にも色々あります。興味のある方は"),t("a",{attrs:{href:"https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式サイト"),t("OutboundLink")],1),s._v("参照。")])]),s._v(" "),t("h3",{attrs:{id:"_3-2-deployment"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-deployment"}},[s._v("#")]),s._v(" 3-2. Deployment")]),s._v(" "),t("p",[s._v("上でも述べた通りDeploymentはPodの稼働状況を管理するオブジェクトです。予め起動するPodの数を指定することで、何かしらの原因でPodが消失しても自動で立ち上げ直してくれたり、逆に多すぎる場合は終了させます。")]),s._v(" "),t("p",[s._v("現在稼働しているPodは、kubectlというcliツールを使って確認できます。\n今は何も稼働してないはずです。")]),s._v(" "),t("blockquote",[t("p",[s._v("【kubectl】")]),s._v(" "),t("p",[s._v("KubernetesのコントロールプレーンにはKubernetesクラスターの構成管理情報にアクセスするためのエンドポイントを提供する"),t("strong",[s._v("kube-apiserver")]),s._v("がありますが、生身の人間がAPIを生で叩いて"),t("strong",[s._v("kube-apiserver")]),s._v("にアクセスするのは少しキツイものがあります。そこでAPIをコマンドで操作できる"),t("strong",[s._v("kubectl")]),s._v("というものがあり、kubectlを使うことによりコマンドベースでAPIを叩くことができます。")])]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl get pods\nNo resources found in default namespace.\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("以下のようなマニフェストファイルを"),t("code",[s._v("app.yml")]),s._v("として作成し、Kubernetesクラスターにデプロイしてみましょう。\n"),t("code",[s._v("image")]),s._v("として指定しているのはサンプル用の簡単なアプリケーションです。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Deployment\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("replicas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("app\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" registry.k8s.io/echoserver"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1.4")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("restartPolicy")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Always\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br")])]),t("blockquote",[t("p",[s._v("【Deploymentにおける必須フィールド】")]),s._v(" "),t("p",[s._v("Kubernetesオブジェクトをマニフェストファイルに記載する際、必ず以下のフィールドに値をセットする必要があります")]),s._v(" "),t("ul",[t("li",[s._v("apiVersion:オブジェクトのAPIVersionを指定")]),s._v(" "),t("li",[s._v("kind:どのオブジェクトを作るかを指定")]),s._v(" "),t("li",[s._v("metadata:オブジェクトを特定するための情報を指定")]),s._v(" "),t("li",[s._v("spec:オブジェクトの状態を指定")])])]),s._v(" "),t("p",[t("code",[s._v("apiVersion")]),s._v("にはオブジェクトのAPIVersionを書きます。\nオブジェクトAPIがどのAPIGROUPに属しているかでapiVersionの書き方が変わってきます。\n今回はDeploymentのオブジェクトなのでそのAPIグループを調べます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl api-resources\nNAME SHORTNAMES APIGROUP NAMESPACED KIND\nbindings true Binding\ncomponentstatuses cs false ComponentStatus\nconfigmaps cm true ConfigMap\n...\ndeployments deploy apps true Deployment\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br")])]),t("p",[s._v("ここではDeploymentが"),t("code",[s._v("apps")]),s._v("に属しているということが分かりました。\nもしAPIGROUPが空の場合はCore groupに属するため、"),t("code",[s._v("apiVersion: v1")]),s._v("で問題ないです。\n次にAPIGROUPで利用可能なversionを調べます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl api-versions | grep apps\napps/v1\napps/v1beta1\napps/v1beta2\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("ここでは3つほど出ましたが、この中の最も新しいversionを使ってください。\n今回は"),t("code",[s._v("apps/v1")]),s._v("を使ってマニフェストファイルを作りました。")]),s._v(" "),t("p",[s._v("yamlを作成したら、以下のコマンドでデプロイできます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl apply -f app.yml\ndeployment.apps/bootcamp created\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("別端末で"),t("code",[s._v("get pods")]),s._v("しながらpodが作られる様子を見てみましょう"),t("code",[s._v("-w")]),s._v("をつけると自動で表示を更新してくれます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl get pods -w\nNAME READY STATUS RESTARTS AGE\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 11s\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 11s\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 83s\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 84s\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br")])]),t("p",[t("code",[s._v("Running")]),s._v("となっていれば無事にアプリケーションが起動しました。今回は"),t("code",[s._v("replicas")]),s._v("に"),t("code",[s._v("2")]),s._v("を指定したのでpodが2個起動しています。"),t("code",[s._v("replicas")]),s._v("の値を変えて再度"),t("code",[s._v("kubectl apply")]),s._v("して遊んでみましょう。")]),s._v(" "),t("h3",{attrs:{id:"_3-3-service"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-service"}},[s._v("#")]),s._v(" 3-3. Service")]),s._v(" "),t("p",[s._v("Podの起動ができましたので、次はPodへのアクセスを試みます。KubernetesクラスターではPod群へのサービスディスカバリーの方法としてServiceオブジェクトが用いられます。Serviceを利用することでPod群に共通のIPアドレスを割り当て、まるで一つの「サービス」であるかのようにアクセスできるようになります。")]),s._v(" "),t("blockquote",[t("p",[s._v("【PodとServiceの関係】")]),s._v(" "),t("p",[s._v("Podは生成の度にIPアドレスが割り振られます。これは何かしらの理由でPodが落ちて別のPodが再生成されるときにもIPアドレスが割り振られますが、落ちたPodと同じIPアドレスが割り振られるとは限りません。こうなった場合に新しいPodへアクセスしたい別Podは新しいPodのIPアドレスがわからなくなってしまいます。ServiceはこのようなPodを共通のIPアドレスで管理し、Podへのアクセスやロードバランシングを行う役割を持っています。また、Serviceの生成によりKubernetesクラスター内の"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/tasks/administer-cluster/coredns/",target:"_blank",rel:"noopener noreferrer"}},[s._v("CoreDNS"),t("OutboundLink")],1),s._v("のA/AAAAレコードやPod内の"),t("code",[s._v("resolve.conf")]),s._v("が自動的に書き換えられるため、Service名を使ってPodへアクセスすることも可能になります。")])]),s._v(" "),t("blockquote",[t("p",[s._v("【ServiceからPodへの通信の受け渡し】")]),s._v(" "),t("p",[s._v("Serviceが作られるとService宛の通信がPodへ転送されますが、その仕組みは"),t("strong",[s._v("ワーカーノード")]),s._v("内のコンポーネントである"),t("strong",[s._v("kube-proxy")]),s._v("によって実現されます。すべてのServiceは基本的にClusterIP(あとで説明します)によるVIPの保持が義務付けられており、またClusterIP配下のPodのIPアドレスはendpointに記載されています。そして、ClusterIPからPodの持つIPへの振り替えを"),t("strong",[s._v("kube-proxy")]),s._v("が行います。"),t("strong",[s._v("kube-proxy")]),s._v("の振り替え方式はいくつか選択肢がありますが、デフォルトの"),t("strong",[s._v("iptableモード")]),s._v("ではiptablesのchainがあり、これによってパケットが転送されます。他のモードについて知りたい方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参照してください。")])]),s._v(" "),t("p",[s._v("先ほどと同じようにServiceのマニフェストファイルを作りましょう。今回は"),t("code",[s._v("service.yml")]),s._v("とします。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("svc\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterIP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" bootcamp\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br")])]),t("p",[s._v("Serviceオブジェクトの中には様々なサービスタイプ種類があり、今回は"),t("code",[s._v("ClusterIP")]),s._v("というサービスタイプを利用しています。ClusterIPはServiceにおけるデフォルト設定であり、明示的に記載が無ければ"),t("code",[s._v("type: ClusterIP")]),s._v("が設定されることに注意してください。")]),s._v(" "),t("blockquote",[t("p",[s._v("【サービスタイプ】")]),s._v(" "),t("p",[s._v("それぞれのServiceの特徴について簡単に触れます。少し長くなるので講義では"),t("code",[s._v("ClusterIP")]),s._v("のみを説明しますが、興味のある人は他のサービスタイプも読んでみてください。")]),s._v(" "),t("h4",{attrs:{id:"clusterip"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#clusterip"}},[s._v("#")]),s._v(" ClusterIP")]),s._v(" "),t("p",[s._v("ClusterIPによって割り振られるIPアドレスはKubernetesクラスター内でのみ有効です。主にクラスター外からアクセスする必要のない箇所などでクラスター内ロードバランスをする際に利用されます。\n"),t("img",{attrs:{src:e(394),alt:"ClusterIP"}})]),s._v(" "),t("h4",{attrs:{id:"nodeport"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#nodeport"}},[s._v("#")]),s._v(" NodePort")]),s._v(" "),t("p",[s._v("ClusterIPを作った上で、全node各々の"),t("code",[s._v("")]),s._v("で受信したアクセスをServiceへ転送することで、クラスタ外からアクセスできるようにします。Docker Swarmでいうところの"),t("code",[s._v("Expose")]),s._v("です。図では全Kubernetes nodeの"),t("code",[s._v("port:30080")]),s._v("へのアクセスを"),t("code",[s._v("NodePort Service")]),s._v("に転送しています。\n"),t("img",{attrs:{src:e(395),alt:"NodePort"}})]),s._v(" "),t("h4",{attrs:{id:"loadbalancer"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#loadbalancer"}},[s._v("#")]),s._v(" LoadBalancer")]),s._v(" "),t("p",[s._v("Kubernetesクラスター外のロードバランサーより払い出された仮想IPアドレスを利用してクラスター外からのアクセスを可能にします。NodePortでは各nodeに"),t("code",[s._v(":")]),s._v("が割り振られ、ユーザはいずれかのアドレス宛にアクセスするため、アクセスしているnodeで障害が起きた際にそのnodeを利用しているユーザはサービスを利用できなくなります。それに対して"),t("code",[s._v("type: LoadBalancer")]),s._v("は、ユーザがクラスター外のロードバランサーから払い出されたIPアドレスのみを知っておくだけでサービスを利用することができます。また、nodeで障害が起きてもそのnodeの切り離しを行うようにクラスター外のロードバランサーを設定することで、ユーザはサービスを継続して利用することができます(ただし従来のロードバランサー+仮想マシンの組み合わせ同様に、障害検知から除外までの間は通信断が発生します)。ここでいうクラスター外のロードバランサーはプロバイダに依存しており、たとえばGCPの場合はGCLBが使われています。\n"),t("img",{attrs:{src:e(396),alt:"LoadBalancer"}})])]),s._v(" "),t("p",[s._v("それでは同じようにapplyしてから"),t("code",[s._v("Service")]),s._v("の稼働状況を確認します。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl apply -f service.yml\nservice/bootcamp-svc created\n$ kubectl get svc\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("S"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" AGE\nbootcamp-svc ClusterIP xxx.xxx.xxx.xxx "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v("/TCP 1h\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br")])]),t("p",[s._v("次に実際にPodにアクセスしてみましょう。"),t("code",[s._v("kubectl proxy")]),s._v("でコントロールプレーンのAPIサーバにポートフォワーディングします。先ほども説明しましたが"),t("code",[s._v("type: ClusterIP")]),s._v("は外から直接アクセスができません。そのため手元のホストからコントロールプレーンまでをポートフォワードし、コントロールプレーンからPodまでをREST APIを使って通信させます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl proxy\nStarting to serve on 127.0.0.1:8001\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("このプロキシ機能はServiceへのアクセスをRESTとして"),t("code",[s._v("/api/v1/namespaces//services/::/proxy/")]),s._v("と表現しているため、今回は"),t("code",[s._v("http://127.0.0.1:8001/api/v1/namespaces//services/bootcamp-svc/proxy/")]),s._v("へアクセスすることでコンテンツを取得することができます。")]),s._v(" "),t("blockquote",[t("p",[t("code",[s._v("")]),s._v("にはデプロイ先のnamespaceを入力します。\nnamespaceがわからない場合は"),t("code",[s._v("kubectl config get-contexts")]),s._v("から探してください。"),t("code",[s._v("CURRENT")]),s._v("に米印が付いているものがいま作業しているコンテキストになります。もし"),t("code",[s._v("NAMESPACE")]),s._v("の欄に何もなければ"),t("code",[s._v("namespace: default")]),s._v("ということになります。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl config get-contexts\nCURRENT NAME CLUSTER AUTHINFO NAMESPACE\n minikube minikube nirazuka\n* nira nirakube nirazuka nirazuka\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])])]),s._v(" "),t("p",[s._v("katacodeを使っている場合、RESTを辿ることができないため"),t("code",[s._v("kubectl port-foward")]),s._v("を利用します。"),t("code",[s._v("kubectl port-foward")]),s._v("はローカルのポートをPodやServiceに直接フォワーディングすることができます。")]),s._v(" "),t("div",{staticClass:"language- line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v("$ kubectl port-forward service/bootcamp-svc --address=0.0.0.0 :80\nForwarding from 0.0.0.0:35715 -> 8080\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br")])]),t("p",[s._v("あとはTerminal横の「+」ボタンから「select port to view on Host 1」を選択し、表示されているポートへアクセスすればコンテンツを取得することができます。")]),s._v(" "),t("p",[t("code",[s._v("Hello Kubernetes!")]),s._v(" が表示されたでしょうか。無事にpodにアクセスすることができました。")]),s._v(" "),t("blockquote",[t("p",[s._v("今回はServiceでアプリケーションを公開しましたが、本来はServiceの上にIngressを作って公開することが推奨されています。\nIngressを利用するとSSLの設定やVirtualHostの設定などを行えるようになります。\n興味のある方は"),t("a",{attrs:{href:"https://kubernetes.io/ja/docs/concepts/services-networking/ingress/",target:"_blank",rel:"noopener noreferrer"}},[s._v("公式ページ"),t("OutboundLink")],1),s._v("を参考に触ってみて下さい。")])]),s._v(" "),t("h3",{attrs:{id:"_3-4-podを削除してみる"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-podを削除してみる"}},[s._v("#")]),s._v(" 3-4. Podを削除してみる")]),s._v(" "),t("p",[s._v("試しに手動で無理やりpodを削除してみましょう。"),t("code",[s._v("kubectl get pods -w")]),s._v("で確認しながら、以下のコマンドでpodを削除してみます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl delete pods "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("pod-name"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("例によってpod-nameはコピペしてください。"),t("code",[s._v("kubectl get pods -w")]),s._v("しているとPodの数が"),t("code",[s._v("replicas")]),s._v("の設定値に合うように新しく起動される様子が分かります。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ kubectl get pods -w\nNAME READY STATUS RESTARTS AGE\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-tq2fs "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Terminating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Pending "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Pending "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 ContainerCreating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 0s\nbootcamp-6bcddb7cf8-ffj7f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 7s\nbootcamp-6bcddb7cf8-jpzg5 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("/1 Terminating "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 23m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br")])]),t("p",[t("code",[s._v("bootcamp-6bcddb7cf8-jpzg5")]),s._v("が手動で削除したpodです。"),t("code",[s._v("bootcamp-6bcddb7cf8-jpzg5")]),s._v("の削除が始まった途端に新しく"),t("code",[s._v("bootcamp-6bcddb7cf8-ffj7f")]),s._v("というpodを立てようとしているのが分かります。")]),s._v(" "),t("p",[s._v("このようにpodがエラーで停止したり、新しいアプリケーションのデプロイなどでpodを停止してもすぐさま"),t("code",[s._v("ReplicaSet")]),s._v("が状態を修復してくれます。\nそれだけではなく、前段の"),t("code",[s._v("Service")]),s._v("がpodの状態を監視しながら通信を流す先を決めてくれるため、一部のpodが停止している間も自動的に生きているpodに通信を流してくれます。")]),s._v(" "),t("p",[s._v("そのためユーザーに一切影響なくpodの停止と復旧が全て自動で可能になっています。このようなインフラをKubernetesとコンテナなしで構築するのはかなり困難です。")]),s._v(" "),t("h2",{attrs:{id:"_4-応用-kubernetesの監視"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-応用-kubernetesの監視"}},[s._v("#")]),s._v(" 4. 応用(Kubernetesの監視)")]),s._v(" "),t("p",[s._v("ここからは本格的なアプリケーションのデプロイを体験してもらいます。katacodeでやっている方はうまくいかないことがあるため本項目は飛ばしてください。")]),s._v(" "),t("p",[s._v("今回Kubernetes上に構築するアプリケーションは監視ツールのPrometheusで、以下の順序でデプロイします。(マニフェストファイルは"),t("a",{attrs:{href:"https://www.hanmoto.com/bd/isbn/9784910313009",target:"_blank",rel:"noopener noreferrer"}},[s._v("Prometheus実践ガイド"),t("OutboundLink")],1),s._v("の内容を一部改変したものを利用しています)")]),s._v(" "),t("ol",[t("li",[s._v("node exporterのデプロイ")]),s._v(" "),t("li",[s._v("RBAC認可を使ってリソースにアクセスするためのアカウントをデプロイ")]),s._v(" "),t("li",[s._v("Prometheusのデプロイ")])]),s._v(" "),t("h3",{attrs:{id:"_4-1-node-exporterのデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-node-exporterのデプロイ"}},[s._v("#")]),s._v(" 4-1. node exporterのデプロイ")]),s._v(" "),t("p",[s._v("node exporterは各ノードのメトリクス情報を収集するツール(exporter)です。これを各nodeに配置する必要がありますが、"),t("code",[s._v("Deployment")]),s._v("オブジェクトを利用すると配置nodeの指定を都度行う必要があり煩雑です。そのため、ここでは"),t("code",[s._v("DeamonSet")]),s._v("オブジェクトを利用します。"),t("code",[s._v("DeamonSet")]),s._v("オブジェクトは各ノードに等しくPodを配置するオブジェクトです。"),t("code",[s._v("node-exporter.yml")]),s._v("という名前で以下の内容のマニフェストファイルを作成します。")]),s._v(" "),t("div",{staticClass:"language-yml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" DaemonSet\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'prom/node-exporter:v1.3.1'")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("hostNetwork")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("hostPID")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token boolean important"}},[s._v("true")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("tolerations")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("key")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("role.kubernetes.io/control"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("plane\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("operator")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Exists\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("value")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("''")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("effect")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" NoSchedule\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" node"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("exporter\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br")])]),t("p",[s._v("各ノードに対して"),t("code",[s._v("prom/node-exporter:v1.3.1")]),s._v("というコンテナを1つずつデプロイさせています。"),t("code",[s._v("hostNetwork")]),s._v("と"),t("code",[s._v("hostPID")]),s._v("を"),t("code",[s._v("true")]),s._v("にすることでノードとコンテナのネットワーク/プロセスIDを共有させます。これは通常、コンテナはホストの環境とプロセス等が分離された状態になっているため、共有させないとPodからノードの情報を取得することができためです。"),t("code",[s._v("node-exporter")]),s._v("は外部から接続させる必要がないため、"),t("code",[s._v("Service")]),s._v("は"),t("code",[s._v("CluserIP")]),s._v("を指定しています。")]),s._v(" "),t("p",[s._v("準備が出来たら"),t("code",[s._v("kubectl apply -f node-exporter.yml")]),s._v("でデプロイします。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f node-exporter.yml")]),s._v("\ndaemonset.apps/node-exporter created\nservice/node-exporter created\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get pods")]),s._v("\nNAME READY STATUS RESTARTS AGE\nnode-exporter-75rpz "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\nnode-exporter-p25gq "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\nnode-exporter-tcbsp "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 47m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br")])]),t("h3",{attrs:{id:"_4-2-rbac認可を使ってリソースにアクセスするためのアカウントをデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-2-rbac認可を使ってリソースにアクセスするためのアカウントをデプロイ"}},[s._v("#")]),s._v(" 4-2. RBAC認可を使ってリソースにアクセスするためのアカウントをデプロイ")]),s._v(" "),t("p",[s._v("KubernetesはRole Based Access Control(RBAC)といわれる、各種リソースへのアクセス制御をユーザロールベースで行っています。そのため、監視に必要なリソースへのアクセスに必要な権限をユーザに付与する必要があります。ここでは権限の定義を行う"),t("code",[s._v("ClusterRole")]),s._v("、権限とユーザとの紐づけを行う"),t("code",[s._v("ClusterRoleBind")]),s._v("という二つのオブジェクトを利用します。"),t("code",[s._v("role-based-access-control.yml")]),s._v("という名前でマニフェストファイルを作り、以下の内容を記載します。")]),s._v(" "),t("div",{staticClass:"language-yaml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRole\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("rules")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroups")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("resources")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" nodes\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" services\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" endpoints\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" pods\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" metrics\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" nodes/metrics\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"list"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"watch"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroups")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" extensions\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("resources")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" ingresses\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"list"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"watch"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("nonResourceURLs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" /metrics\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("verbs")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"get"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRoleBinding\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("roleRef")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiGroup")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" rbac.authorization.k8s.io\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterRole\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("subjects")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ServiceAccount\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ServiceAccount\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br")])]),t("p",[t("code",[s._v("default")]),s._v("namespace上の"),t("code",[s._v("prometheus")]),s._v("というアカウントに対して、各種リソースへの参照権限を付与する内容になります。"),t("code",[s._v("kubectl apply -f role-based-access-control.yml")]),s._v("を実行してデプロイします。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f role-based-access-control.yml ")]),s._v("\nclusterrole.rbac.authorization.k8s.io/prometheus created\nclusterrolebinding.rbac.authorization.k8s.io/prometheus created\nserviceaccount/prometheus created\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br")])]),t("p",[s._v("これにより、API Serverなどへのアクセスするための認証情報が払い出されました。")]),s._v(" "),t("h3",{attrs:{id:"_4-3-prometheusのデプロイ"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-prometheusのデプロイ"}},[s._v("#")]),s._v(" 4-3. Prometheusのデプロイ")]),s._v(" "),t("p",[s._v("最後にPrometheusのデプロイを行います。Prometheusのデプロイには"),t("code",[s._v("Deployment")]),s._v("と"),t("code",[s._v("Service")]),s._v("オブジェクトを利用しますが、Prometheus自体の設定ファイルは"),t("code",[s._v("ConfigMap")]),s._v("というオブジェクトを利用して定義します。これを利用することによりコンフィグファイルをマニフェストファイルとして管理することができ、さらにPrometheusに反映させることが出来ます。"),t("code",[s._v("prometheus.yml")]),s._v("というマニフェストファイルを作り以下の内容を記載します。")]),s._v(" "),t("div",{staticClass:"language-yaml line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" apps/v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Deployment\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" default\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("replicas")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("matchLabels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("template")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("serviceAccountName")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containers")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("image")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prom/prometheus"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("v2.33.3\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("imagePullPolicy")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" IfNotPresent\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("args")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("config.file=/prometheus/prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("log.level=debug\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("web.enable"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v("lifecycle\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("containerPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("volumeMounts")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("mountPath")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" /prometheus/prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("subPath")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus.yml\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("volumes")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("configMap")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" Service\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("ports")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("-")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" http\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("port")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("protocol")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" TCP\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("targetPort")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("selector")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("type")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ClusterIP\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("---")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" v1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" ConfigMap\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("labels")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("app")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" prometheus\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("data")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[s._v("prometheus.yml")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("|")]),t("span",{pre:!0,attrs:{class:"token scalar string"}},[s._v("\n global:\n scrape_interval: 15s\n scrape_configs:\n - job_name: 'prometheus'\n kubernetes_sd_configs:\n - role: pod\n relabel_configs:\n - source_labels: [__meta_kubernetes_pod_name]\n regex: prometheus-.+\n action: keep\n - job_name: 'apiserver'\n kubernetes_sd_configs:\n - role: service\n scheme: https\n tls_config:\n ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n authorization:\n credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token\n relabel_configs:\n - source_labels:\n - __meta_kubernetes_namespace\n - __meta_kubernetes_service_name\n - __meta_kubernetes_service_port_name\n action: keep\n regex: default;kubernetes;https\n - job_name: 'node-exporter'\n scheme: http\n kubernetes_sd_configs:\n - role: node\n relabel_configs:\n - source_labels: [__address__]\n action: replace\n regex: (.+):.+\n replacement: ${1}:9100\n target_label: __address__")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br"),t("span",{staticClass:"line-number"},[s._v("26")]),t("br"),t("span",{staticClass:"line-number"},[s._v("27")]),t("br"),t("span",{staticClass:"line-number"},[s._v("28")]),t("br"),t("span",{staticClass:"line-number"},[s._v("29")]),t("br"),t("span",{staticClass:"line-number"},[s._v("30")]),t("br"),t("span",{staticClass:"line-number"},[s._v("31")]),t("br"),t("span",{staticClass:"line-number"},[s._v("32")]),t("br"),t("span",{staticClass:"line-number"},[s._v("33")]),t("br"),t("span",{staticClass:"line-number"},[s._v("34")]),t("br"),t("span",{staticClass:"line-number"},[s._v("35")]),t("br"),t("span",{staticClass:"line-number"},[s._v("36")]),t("br"),t("span",{staticClass:"line-number"},[s._v("37")]),t("br"),t("span",{staticClass:"line-number"},[s._v("38")]),t("br"),t("span",{staticClass:"line-number"},[s._v("39")]),t("br"),t("span",{staticClass:"line-number"},[s._v("40")]),t("br"),t("span",{staticClass:"line-number"},[s._v("41")]),t("br"),t("span",{staticClass:"line-number"},[s._v("42")]),t("br"),t("span",{staticClass:"line-number"},[s._v("43")]),t("br"),t("span",{staticClass:"line-number"},[s._v("44")]),t("br"),t("span",{staticClass:"line-number"},[s._v("45")]),t("br"),t("span",{staticClass:"line-number"},[s._v("46")]),t("br"),t("span",{staticClass:"line-number"},[s._v("47")]),t("br"),t("span",{staticClass:"line-number"},[s._v("48")]),t("br"),t("span",{staticClass:"line-number"},[s._v("49")]),t("br"),t("span",{staticClass:"line-number"},[s._v("50")]),t("br"),t("span",{staticClass:"line-number"},[s._v("51")]),t("br"),t("span",{staticClass:"line-number"},[s._v("52")]),t("br"),t("span",{staticClass:"line-number"},[s._v("53")]),t("br"),t("span",{staticClass:"line-number"},[s._v("54")]),t("br"),t("span",{staticClass:"line-number"},[s._v("55")]),t("br"),t("span",{staticClass:"line-number"},[s._v("56")]),t("br"),t("span",{staticClass:"line-number"},[s._v("57")]),t("br"),t("span",{staticClass:"line-number"},[s._v("58")]),t("br"),t("span",{staticClass:"line-number"},[s._v("59")]),t("br"),t("span",{staticClass:"line-number"},[s._v("60")]),t("br"),t("span",{staticClass:"line-number"},[s._v("61")]),t("br"),t("span",{staticClass:"line-number"},[s._v("62")]),t("br"),t("span",{staticClass:"line-number"},[s._v("63")]),t("br"),t("span",{staticClass:"line-number"},[s._v("64")]),t("br"),t("span",{staticClass:"line-number"},[s._v("65")]),t("br"),t("span",{staticClass:"line-number"},[s._v("66")]),t("br"),t("span",{staticClass:"line-number"},[s._v("67")]),t("br"),t("span",{staticClass:"line-number"},[s._v("68")]),t("br"),t("span",{staticClass:"line-number"},[s._v("69")]),t("br"),t("span",{staticClass:"line-number"},[s._v("70")]),t("br"),t("span",{staticClass:"line-number"},[s._v("71")]),t("br"),t("span",{staticClass:"line-number"},[s._v("72")]),t("br"),t("span",{staticClass:"line-number"},[s._v("73")]),t("br"),t("span",{staticClass:"line-number"},[s._v("74")]),t("br"),t("span",{staticClass:"line-number"},[s._v("75")]),t("br"),t("span",{staticClass:"line-number"},[s._v("76")]),t("br"),t("span",{staticClass:"line-number"},[s._v("77")]),t("br"),t("span",{staticClass:"line-number"},[s._v("78")]),t("br"),t("span",{staticClass:"line-number"},[s._v("79")]),t("br"),t("span",{staticClass:"line-number"},[s._v("80")]),t("br"),t("span",{staticClass:"line-number"},[s._v("81")]),t("br"),t("span",{staticClass:"line-number"},[s._v("82")]),t("br"),t("span",{staticClass:"line-number"},[s._v("83")]),t("br"),t("span",{staticClass:"line-number"},[s._v("84")]),t("br"),t("span",{staticClass:"line-number"},[s._v("85")]),t("br"),t("span",{staticClass:"line-number"},[s._v("86")]),t("br"),t("span",{staticClass:"line-number"},[s._v("87")]),t("br"),t("span",{staticClass:"line-number"},[s._v("88")]),t("br"),t("span",{staticClass:"line-number"},[s._v("89")]),t("br"),t("span",{staticClass:"line-number"},[s._v("90")]),t("br"),t("span",{staticClass:"line-number"},[s._v("91")]),t("br"),t("span",{staticClass:"line-number"},[s._v("92")]),t("br"),t("span",{staticClass:"line-number"},[s._v("93")]),t("br"),t("span",{staticClass:"line-number"},[s._v("94")]),t("br"),t("span",{staticClass:"line-number"},[s._v("95")]),t("br"),t("span",{staticClass:"line-number"},[s._v("96")]),t("br"),t("span",{staticClass:"line-number"},[s._v("97")]),t("br"),t("span",{staticClass:"line-number"},[s._v("98")]),t("br"),t("span",{staticClass:"line-number"},[s._v("99")]),t("br")])]),t("p",[s._v("Prometheusの設定の詳細については割愛しますが、4-2ににて発行した認証情報は"),t("code",[s._v("tls_config")]),s._v("ならびに"),t("code",[s._v("authorization")]),s._v("で指定しています。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Prometheus講義受講者向け】")]),s._v(" "),t("p",[s._v("Prometheusの講義内で「Prometheusの特徴の1つにサービスディスカバリがあり、監視対象を動的に取得することができる」と話しました。\nそのサービスディスカバリは"),t("code",[s._v("kubernetes_sd_configs")]),s._v("の部分で設定しています。"),t("code",[s._v("role")]),s._v("という概念を利用してKubernetes内の各種リソースを動的に取得します。"),t("code",[s._v("role")]),s._v("で取得できるリソースは以下の5つです。")]),s._v(" "),t("ul",[t("li",[s._v("Node")]),s._v(" "),t("li",[s._v("Service")]),s._v(" "),t("li",[s._v("Endpoints")]),s._v(" "),t("li",[s._v("Pod")]),s._v(" "),t("li",[s._v("Ingress")])])]),s._v(" "),t("p",[t("code",[s._v("kubectl apply -f prometheus.yml")]),s._v("でPrometheusをデプロイし、確認を行います。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl apply -f prometheus.yml ")]),s._v("\nservice/prometheus created\ndeployment.apps/prometheus created\nconfigmap/prometheus created\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl get all")]),s._v("\nNAME READY STATUS RESTARTS AGE\npod/node-exporter-75rpz "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/node-exporter-p25gq "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/node-exporter-tcbsp "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\npod/prometheus-76b579c56c-r7nps "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 Running "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 115m\n\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("S"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" AGE\nservice/kubernetes ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".0.1 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("443")]),s._v("/TCP 29h\nservice/node-exporter ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".16.136 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9100")]),s._v("/TCP 115m\nservice/prometheus ClusterIP "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.96")]),s._v(".128.27 "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("9090")]),s._v("/TCP 115m\n\nNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE\ndaemonset.apps/node-exporter "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("none"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" 115m\n\nNAME READY UP-TO-DATE AVAILABLE AGE\ndeployment.apps/prometheus "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("/1 "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" 115m\n\nNAME DESIRED CURRENT READY AGE\nreplicaset.apps/prometheus-76b579c56c "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" 115m\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br"),t("span",{staticClass:"line-number"},[s._v("14")]),t("br"),t("span",{staticClass:"line-number"},[s._v("15")]),t("br"),t("span",{staticClass:"line-number"},[s._v("16")]),t("br"),t("span",{staticClass:"line-number"},[s._v("17")]),t("br"),t("span",{staticClass:"line-number"},[s._v("18")]),t("br"),t("span",{staticClass:"line-number"},[s._v("19")]),t("br"),t("span",{staticClass:"line-number"},[s._v("20")]),t("br"),t("span",{staticClass:"line-number"},[s._v("21")]),t("br"),t("span",{staticClass:"line-number"},[s._v("22")]),t("br"),t("span",{staticClass:"line-number"},[s._v("23")]),t("br"),t("span",{staticClass:"line-number"},[s._v("24")]),t("br"),t("span",{staticClass:"line-number"},[s._v("25")]),t("br")])]),t("h3",{attrs:{id:"_4-4-prometheusの確認"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-4-prometheusの確認"}},[s._v("#")]),s._v(" 4-4. Prometheusの確認")]),s._v(" "),t("p",[s._v("ひと通りのアプリケーションのデプロイが完了したので、さっそくアクセスします。Prometheusは"),t("code",[s._v("ClusterIP")]),s._v("の配下にあるため、ポートフォワーディングしてあげます。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# kubectl port-forward svc/prometheus --address 0.0.0.0 8080:9090")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("ブラウザからアクセスし、"),t("code",[s._v("Status")]),s._v("タブの"),t("code",[s._v("Targets")]),s._v("を開いて全て問題なく取得できていれば完了です。\n"),t("img",{attrs:{src:"images/prometheus_main-menu.png",alt:"prometheus_main-nemu"}}),s._v("\nこれでKuberentes上の各コンポーネントに対して監視を行うことが出来ました。")]),s._v(" "),t("blockquote",[t("p",[s._v("【Prometheus講義を受講した人向け】")]),s._v(" "),t("p",[s._v("式ブラウザから各種APIオブジェクトのメトリクス情報を取得してみてください。\nまた、Kubernetes上で動くアプリケーションの監視にはkube-state-metricsやcAdvidsorといったエクスポートを利用します。余裕のある人はPodの監視も行ってみてください。")])]),s._v(" "),t("h2",{attrs:{id:"_5-最後に"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_5-最後に"}},[s._v("#")]),s._v(" 5. 最後に")]),s._v(" "),t("p",[s._v("Kubernetesの紹介と代表的なオブジェクトである"),t("code",[s._v("Deployment")]),s._v("と"),t("code",[s._v("Service")]),s._v("について簡単に触ってみました。\nKubetenetesでは他にも様々なオブジェクトや設定を使います。")]),s._v(" "),t("p",[s._v("例えば")]),s._v(" "),t("ul",[t("li",[s._v("アプリケーションの環境変数を設定するために"),t("code",[s._v("env")]),s._v("を使う")]),s._v(" "),t("li",[s._v("データベースなどステートフルなpodを稼働させるために"),t("code",[s._v("StatefulSet")]),s._v("を使う")]),s._v(" "),t("li",[s._v("データの永続化のため"),t("code",[s._v("PersistentVolume")]),s._v("や"),t("code",[s._v("PersistentVolumeClaim")]),s._v("を使う")]),s._v(" "),t("li",[s._v("アプリケーションのコンフィグファイルを管理するのに"),t("code",[s._v("ConfigMap")]),s._v("を使う")]),s._v(" "),t("li",[s._v("APIキーやパスワードなど秘密情報を扱うために"),t("code",[s._v("Secret")]),s._v("を使う(ただしキー値はbase64でエンコードされた文字列)")])]),s._v(" "),t("p",[s._v("などなどです。"),t("code",[s._v("PersistentVolume")]),s._v("や"),t("code",[s._v("PersistentVolumeClaim")]),s._v("などはディストリビューションごとに扱い方が違ったりしますし、構築したいアプリケーションによってマニフェストファイルの書き方は様々なので今回は割愛しました。")]),s._v(" "),t("p",[s._v("社内でKubetenetesを使ってアプリケーションを構築する場合はIKEが使いやすいかと思いますので、ぜひチュートリアルなどを眺めてみてください。")]),s._v(" "),t("blockquote",[t("p",[s._v("【参考文献】")]),s._v(" "),t("ol",[t("li",[s._v("Kubernetes完全ガイド/青山信也(インプレス)")]),s._v(" "),t("li",[s._v("イラストでわかるDockerとKubernetes/徳永航平(技術評論社)")]),s._v(" "),t("li",[s._v("Docker/Kubernetes実践コンテナ開発入門/山田明憲(技術評論社)")]),s._v(" "),t("li",[t("a",{attrs:{href:"https://kubernetes.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Kubernetes公式ドキュメント"),t("OutboundLink")],1),s._v("/CNCF")]),s._v(" "),t("li",[s._v("Prometheus実践ガイド/仲亀拓馬(テッキーメディア)")])])])],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/15.b528c6e2.js b/assets/js/15.fbc41b18.js similarity index 99% rename from assets/js/15.b528c6e2.js rename to assets/js/15.fbc41b18.js index 3f1f5461..ba3ea6a1 100644 --- a/assets/js/15.b528c6e2.js +++ b/assets/js/15.fbc41b18.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{474:function(s,a,t){s.exports=t.p+"assets/img/apache-start.c57e81f7.png"},475:function(s,a,t){s.exports=t.p+"assets/img/site-80.1afd6993.png"},476:function(s,a,t){s.exports=t.p+"assets/img/site-82.9465a06d.png"},477:function(s,a,t){s.exports=t.p+"assets/img/nginx_html.ae5a2fc7.png"},478:function(s,a,t){s.exports=t.p+"assets/img/nginx-proxy.drawio.50845ff4.png"},545:function(s,a,t){"use strict";t.r(a);var n=t(10),e=Object(n.a)({},(function(){var s=this,a=s._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"apache-nginx-を触ってみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-nginx-を触ってみよう"}},[s._v("#")]),s._v(" Apache + Nginx を触ってみよう")]),s._v(" "),a("h2",{attrs:{id:"事前準備"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#事前準備"}},[s._v("#")]),s._v(" 事前準備")]),s._v(" "),a("p",[s._v("以下のように"),a("code",[s._v("docker pull")]),s._v("をしたあと、ハンズオン用のコンテナを立ち上げてログインしてください。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" pull python:3.8.17-bookworm")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("3.8.17-bookworm: Pulling from library/python\nd52e4f012db1: Pull complete\n7dd206bea61f: Pull complete\n2320f9be4a9c: Pull complete\n6e5565e0ba8d: Pull complete\nd3797e13cc41: Pull complete\n9d8ab9ac5a7d: Pull complete\n43ed38f1d568: Pull complete\n164b4060be55: Pull complete\nDigest: sha256:2ee706fa11ec6907a27f1c5116e9749ad1267336b3b0d53fc35cfba936fae32e\nStatus: Downloaded newer image for python:3.8.17-bookworm\ndocker.io/library/python:3.8.17-bookworm\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" run --rm -itd --name test-debian -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v(":80 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8082")]),s._v(":82 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8088")]),s._v(":88 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8089")]),s._v(":89 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8443")]),s._v(":443 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8444")]),s._v(":444 python:3.8.17-bookworm /bin/bash")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("a0da070e286fd52ebb323e5faff9c960014bfcd8eb1e509cb5a12daa9fb9a85e\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("exec")]),s._v(" -it test-debian /bin/bash")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("root@a0da070e286f:/#\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br")])]),a("p",[s._v("Apacheとnginxをインストールします。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("apt")]),s._v(" update")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]\nGet:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]\nGet:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]\nGet:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8906 kB]\nGet:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [4732 B]\nGet:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [48.0 kB]\nFetched 9210 kB in 3s (3184 kB/s)\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\n10 packages can be upgraded. Run 'apt list --upgradable' to see them.\n\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("apt")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" -y apache2 apache2-dev nginx "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")])])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Reading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following additional packages will be installed:\n apache2-bin apache2-data apache2-utils autopoint bsdextrautils debhelper dh-autoreconf dh-strip-nondeterminism dwz gettext gettext-base groff-base intltool-debian iproute2\n libapr1-dev libaprutil1-dbd-sqlite3 libaprutil1-dev libaprutil1-ldap libarchive-cpio-perl libarchive-zip-perl libatm1 libbpf1 libcap2-bin libdebhelper-perl\n libfile-stripnondeterminism-perl libgpm2 libldap-dev libldap2-dev liblua5.3-0 libmail-sendmail-perl libmnl0 libpam-cap libpipeline1 libsctp-dev libsctp1 libsodium23\n libsub-override-perl libsys-hostname-long-perl libuchardet0 libxtables12 man-db nginx-common po-debconf ssl-cert vim-common vim-runtime xxd\n\n~~~略~~~\n\nSetting up libapr1-dev (1.7.2-3) ...\nSetting up libaprutil1-dev (1.6.3-1) ...\nSetting up debhelper (13.11.4) ...\nSetting up apache2-dev (2.4.57-2) ...\nProcessing triggers for libc-bin (2.36-9) ...\nProcessing triggers for hicolor-icon-theme (0.17-2) ...\nroot@a0da070e286f:/#\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br"),a("span",{staticClass:"line-number"},[s._v("18")]),a("br"),a("span",{staticClass:"line-number"},[s._v("19")]),a("br"),a("span",{staticClass:"line-number"},[s._v("20")]),a("br"),a("span",{staticClass:"line-number"},[s._v("21")]),a("br"),a("span",{staticClass:"line-number"},[s._v("22")]),a("br"),a("span",{staticClass:"line-number"},[s._v("23")]),a("br"),a("span",{staticClass:"line-number"},[s._v("24")]),a("br"),a("span",{staticClass:"line-number"},[s._v("25")]),a("br"),a("span",{staticClass:"line-number"},[s._v("26")]),a("br"),a("span",{staticClass:"line-number"},[s._v("27")]),a("br"),a("span",{staticClass:"line-number"},[s._v("28")]),a("br"),a("span",{staticClass:"line-number"},[s._v("29")]),a("br"),a("span",{staticClass:"line-number"},[s._v("30")]),a("br"),a("span",{staticClass:"line-number"},[s._v("31")]),a("br"),a("span",{staticClass:"line-number"},[s._v("32")]),a("br")])]),a("p",[s._v("以下のコマンドでバージョンが表示されれば成功です。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[s._v("apache2 -v")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Server version: Apache/2.4.57 (Debian)\nServer built: 2023-04-13T03:26:51\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[s._v("nginx -v")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("nginx version: nginx/1.22.1\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br")])]),a("h2",{attrs:{id:"webサーバー"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#webサーバー"}},[s._v("#")]),s._v(" Webサーバー")]),s._v(" "),a("p",[s._v("いわゆる「Webサーバー」とは、HTTP(Hypertext Transfer Protocol)でリクエストを受け、HTTPでレスポンスを返すソフトウェアの通称です。\n僕らがブラウザなどにURLを入力したりリンクをクリックした時、Webページが表示されるのはWebサーバーが要求したURLに対するレスポンスを返しているからです。またスマホアプリの裏で行われるサーバーとのやりとりには多くの場合HTTPが使われており、ここでもWebサーバーがゲームのデータなどをレスポンスとして返しています。")]),s._v(" "),a("p",[s._v("Webサーバのシンプルな機能は前述の通りですが、実際にはユースケースに合わせてさまざまな役割を持ちます。")]),s._v(" "),a("ul",[a("li",[s._v("HTMLやテキストファイルの配信")]),s._v(" "),a("li",[s._v("動的アプリケーションのホスティング\n"),a("ul",[a("li",[s._v("JavaやPythonやPHPなど、プログラムで生成されたレスポンスを返す")])])]),s._v(" "),a("li",[s._v("HTTP通信を別のサーバーに中継するプロキシ")]),s._v(" "),a("li",[s._v("Basic認証などによる認証処理")]),s._v(" "),a("li",[s._v("ACL(Access Control List)によるアクセス制御・不正な通信への防御")])]),s._v(" "),a("p",[s._v("簡単なWebサーバーであればどのプログラミング言語でも比較的簡単に作ることができます。\nしかし実用上はさまざまな機能をもち、セキュリティやパフォーマンスについても長年改善されてきた専用のソフトウェアが必要になり、それがいわゆる「Webサーバーソフトウェア」と呼ばれるツールです。")]),s._v(" "),a("p",[s._v("有名どころを挙げてみると")]),s._v(" "),a("ul",[a("li",[s._v("Apache HTTP Server")]),s._v(" "),a("li",[s._v("IIS")]),s._v(" "),a("li",[s._v("lighttpd")]),s._v(" "),a("li",[s._v("nginx")])]),s._v(" "),a("p",[s._v("あたりでしょうか。Linuxサーバー上で動かすのであればほぼApacheとnginxの2択になると思います。")]),s._v(" "),a("p",[s._v("また最近ではenvoyやtraefikなど、クラウドやKubernetesという文脈ではプロキシ機能に特化したソフトウェアが使われることも多くなりました。")]),s._v(" "),a("h2",{attrs:{id:"apache-と-nginx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-と-nginx"}},[s._v("#")]),s._v(" Apache と Nginx")]),s._v(" "),a("h3",{attrs:{id:"apache-http-server"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-http-server"}},[s._v("#")]),s._v(" Apache HTTP Server")]),s._v(" "),a("p",[s._v("「Apache HTTP Server」はnginxと並んで2大勢力を誇っているWebサーバソフトウェアのひとつです。 CentOSではhttpdという名前になっていたり、単にApacheと呼ばれます。")]),s._v(" "),a("p",[s._v("「Apache HTTP Server」は「Apacheソフトウェア財団」によって管理されるOSSで、20年以上の歴史を持ちます。 世界的にもっとも普及したWebサーバで、LAMP(Linux, Apache, MySQL, PHP)環境のひとつにも挙げられ、nginxと並んで2大勢力を誇ります。\n(参考: "),a("a",{attrs:{href:"https://www.netcraft.com/blog/june-2023-web-server-survey/",target:"_blank",rel:"noopener noreferrer"}},[s._v("June 2023 Web Server Survey"),a("OutboundLink")],1),s._v(")")]),s._v(" "),a("p",[s._v("正式名称は「Apache HTTP Server」ですが、歴史的経緯などからCentOSではhttpdという名前になっていたり、単にApacheと呼ばれたりします。")]),s._v(" "),a("p",[s._v("以前は大量のリクエストを受けた際にプロセスをforkできず、リクエストを捌き切れなくなる(いわゆるC10K問題)ことが問題視されました。 その際nginxをはじめとして新しいWebサーバーソフトウェアが登場しましたが、Apache自体もworkerやevent MPMといった新しい仕組みを導入し、動作も安定していることからいまだに高いシェアを占めています。")]),s._v(" "),a("h3",{attrs:{id:"nginx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nginx"}},[s._v("#")]),s._v(" nginx")]),s._v(" "),a("p",[s._v("nginxは2004年頃、当時のWebサーバーが抱えていたパフォーマンス問題(C10K問題)の解決を背景に開発が進められました。\n当時からApache 2.2は高機能で信頼性が高く、ある種成熟したソフトウェアでしたが、それに対してnginxは軽量さと高パフォーマンスに焦点をあてて開発されており、Apacheのカバーしきれないユースケースに対して力を発揮しました。")]),s._v(" "),a("p",[s._v("特に後段のサーバーにリクエストを流すリバースプロキシ・ロードバランサ機能がとても使いやすく、どちらかというと軽量なリクエストを大量に捌くのに向いています。")]),s._v(" "),a("h2",{attrs:{id:"apache-ハンズオン"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-ハンズオン"}},[s._v("#")]),s._v(" Apache ハンズオン")]),s._v(" "),a("h3",{attrs:{id:"htmlファイルの配信-check1"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#htmlファイルの配信-check1"}},[s._v("#")]),s._v(" HTMLファイルの配信(check1)")]),s._v(" "),a("p",[s._v("まずはApacheを起動しましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 start")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("ブラウザを開いて"),a("a",{attrs:{href:"http://localhost:8080",target:"_blank",rel:"noopener noreferrer"}},[s._v("localhost:8080"),a("OutboundLink")],1),s._v("にアクセスしてみてください。以下のような画面が表示されれば成功です。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(474),alt:"apache-start"}})]),s._v(" "),a("p",[s._v("表示されたページはデフォルトのHTMLファイルです。これを自分で作成したページに置き換えてみましょう。 デフォルトではDocument Rootは/var/www/html/に設定されています。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("Document RootはApacheが静的ファイルを配信するためのroot directoryです。")])]),s._v(" "),a("p",[s._v("この下にある"),a("code",[s._v("index.html")]),s._v("ファイルを自分の物に置き換えてみましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mv")]),s._v(" /var/www/html/index.html /var/www/html/_index.html")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Hello Bootcamp!!'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" /var/www/html/index.html")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("再び"),a("code",[s._v("http://localhost:8080/")]),s._v("を開くと"),a("code",[s._v("Hello Bootcamp!!")]),s._v("が表示されるのを確認してください。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[a("code",[s._v("http://localhost:8080/")]),s._v(" のようにファイル名を指定せずディレクトリ(この場合はルートディレクトリ)を指定した場合、Apacheは"),a("code",[s._v("index.html")]),s._v("を返すようにデフォルトで設定されています。\nこの設定は変更できます。")])]),s._v(" "),a("p",[s._v("Document Root配下にディレクトリを作成するとブラウザからも同様にアクセスできます。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mkdir")]),s._v(" /var/www/html/hoge")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Hello HUGA!!'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" /var/www/html/hoge/huga.txt")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("code",[s._v("http://localhost:8080/hoge/huga.txt")]),s._v(" にアクセスすると追加したファイルが表示されます。")]),s._v(" "),a("p",[s._v("アクセスログも確認してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# tail /var/log/apache2/access.log")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("h3",{attrs:{id:"virtualhost-の設定-check2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#virtualhost-の設定-check2"}},[s._v("#")]),s._v(" VirtualHost の設定(check2)")]),s._v(" "),a("p",[s._v("1つのApacheで複数のWebサイトを管理したいことがあります。異なるIPアドレスやアドレス、port番号からアクセスされた時にDocument Rootなどを切り替えたいときは"),a("code",[s._v("VirtualHost")]),s._v("を設定することで実現できます。")]),s._v(" "),a("p",[s._v("ここではport番号を"),a("code",[s._v("80")]),s._v("と"),a("code",[s._v("82")]),s._v("に分けて別々のWebサイトを設定してみます。\n(docker起動時にport forwardしているため、手元からは"),a("code",[s._v("8080")]),s._v("と"),a("code",[s._v("8082")]),s._v("からアクセスできます。)")]),s._v(" "),a("p",[s._v("まずは新しくDocument RootになるディレクトリとHTMLファイルを作成します。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /var/www/html/site-80")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /var/www/html/site-82")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# echo 'This is site 80!' > /var/www/html/site-80/index.html")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# echo 'This is site 82!' > /var/www/html/site-82/index.html")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br")])]),a("p",[s._v("次にApacheの設定をして行きます。やることは")]),s._v(" "),a("ul",[a("li",[s._v("listen portに82を追加")]),s._v(" "),a("li",[s._v("virtual host設定の追加")])]),s._v(" "),a("p",[s._v("の2つです。listen portの追加は"),a("code",[s._v("/etc/apache2/ports.conf")]),s._v("に書きましょう。\n以下のように"),a("code",[s._v("Listen 80")]),s._v(" の下に "),a("code",[s._v("Listen 82")]),s._v("の記述を追加します。")]),s._v(" "),a("div",{staticClass:"language-apache line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[s._v("# If you just change the port or add more ports here, you will likely also\n# have to change the VirtualHost statement in\n# /etc/apache2/sites-enabled/000-default.conf\n\nListen 80\nListen 82\n\n\n Listen 443\n\n\n\n Listen 443\n\n\n# vim: syntax=apache ts=4 sw=4 sts=4 sr noet\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br")])]),a("p",[s._v("VitrualHostの設定は"),a("code",[s._v("/etc/apache2/sites-available")]),s._v("の下に作成して行きます。")]),s._v(" "),a("p",[a("code",[s._v("/etc/apache2/sites-available/site-80.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("80")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-80\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[a("code",[s._v("/etc/apache2/sites-available/site-82.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("82")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-82\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("設定ファイルを作成したら"),a("code",[s._v("a2dissite")]),s._v("、"),a("code",[s._v("a2ensite")]),s._v("コマンドを使って設定を有効化しましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2dissite 000-default")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2ensite site-80")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2ensite site-82")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[a("code",[s._v("a2dissite")]),s._v("や"),a("code",[s._v("a2ensite")]),s._v("といったコマンドは実はapache本体の機能ではありません。"),a("code",[s._v("a2ensite")]),s._v("は"),a("code",[s._v("/etc/apache2/sites-available")]),s._v("以下のファイルのsymlinkを"),a("code",[s._v("/etc/apache2/sites-enable")]),s._v("以下に追加するだけのコマンドです。\n実際のApacheは"),a("code",[s._v("/etc/apache2/sites-enable")]),s._v("以下のコンフィグファイルをloadしているため、コマンドによってサイトが有効化されたように見えるのです。")]),s._v(" "),a("p",[s._v("CentOSなど他のディストリビューションでは、これらのコマンドが存在しないことが多いので注意してください。")])]),s._v(" "),a("p",[s._v("そしてApacheをリスタートします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# service apache2 reload")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[a("code",[s._v("localhost:8080")]),s._v("と"),a("code",[s._v("localhost:8082")]),s._v("にアクセスしてみてください。意図通りの挙動になっているでしょうか。")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("img",{attrs:{src:t(475),alt:"site-80"}})])])]),s._v(" "),a("tbody")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("img",{attrs:{src:t(476),alt:"site-82"}})])])]),s._v(" "),a("tbody")]),s._v(" "),a("h2",{attrs:{id:"nginx-ハンズオン"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nginx-ハンズオン"}},[s._v("#")]),s._v(" nginx ハンズオン")]),s._v(" "),a("h3",{attrs:{id:"htmlファイルの配信-check3"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#htmlファイルの配信-check3"}},[s._v("#")]),s._v(" HTMLファイルの配信(check3)")]),s._v(" "),a("p",[s._v("次はnginxを使って同じことをしてみましょう。")]),s._v(" "),a("p",[s._v("80 portはすでにApacheが使っているため、nginxのサイトは88 portでリクエストを受け付けるようにします。")]),s._v(" "),a("div",{staticClass:"language-bash line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# vim /etc/nginx/sites-enabled/default")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("div",{staticClass:"language-nginx line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nginx"}},[a("code",[a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("88")]),s._v(" default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 80 => 88 に変更")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" [::]:88 default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 80 => 88 に変更")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("root")]),s._v(" /var/www/html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("index")]),s._v(" index.html index.htm index.nginx-debian.html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server_name")]),s._v(" _")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("location")]),s._v(" /")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("try_files")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$uri")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$uri")]),s._v("/ =404")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br")])]),a("p",[s._v("変更したらnginxを起動しましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" nginx start")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("[ ok ] Starting nginx: nginx.\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("a",{attrs:{href:"http://localhost:8088",target:"_blank",rel:"noopener noreferrer"}},[s._v("localhost:8088"),a("OutboundLink")],1),s._v(" にアクセスしてみてください。さっき作った"),a("code",[s._v("Hello Bootcamp!!")]),s._v("のHTMLが見えていれば成功です。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(477),alt:"nginx_html"}})]),s._v(" "),a("p",[s._v("アクセスログも確認してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# tail /var/log/nginx/access.log")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("h3",{attrs:{id:"ロードバランス-check4"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ロードバランス-check4"}},[s._v("#")]),s._v(" ロードバランス(check4)")]),s._v(" "),a("p",[s._v("nginxのプロキシ・ロードバランス機能を使ってみましょう。以下のような構成を作ってみます。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(478),alt:"nginx_proxy"}})]),s._v(" "),a("p",[a("code",[s._v("localhost:8089")]),s._v("にアクセスすると、先ほどApacheで作ったsite-80とsite-89のどちらかにランダムでリクエストをプロキシするようにします。")]),s._v(" "),a("p",[s._v("そのための設定を"),a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v("に書いていきます。")]),s._v(" "),a("div",{staticClass:"language-nginx line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nginx"}},[a("code",[a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("upstream")]),s._v(" backend")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")]),s._v(" localhost:80 weight=1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")]),s._v(" localhost:82 weight=1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("89")]),s._v(" default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" [::]:89 default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("index")]),s._v(" index.html index.htm index.nginx-debian.html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server_name")]),s._v(" _")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("location")]),s._v(" /")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("proxy_pass")]),s._v(" http://backend")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br")])]),a("p",[a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v("を作成したらnginxをリスタートしましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" nginx restart")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("[ ok ] Restarting nginx: nginx.\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("a",{attrs:{href:"http://localhost:8089/",target:"_blank",rel:"noopener noreferrer"}},[s._v("http://localhost:8089/"),a("OutboundLink")],1),s._v(" にアクセスしてみてください。\nsite-80とsite-82がランダムで表示されたでしょうか。")]),s._v(" "),a("h3",{attrs:{id:"https-対応-check5"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#https-対応-check5"}},[s._v("#")]),s._v(" https 対応(check5)")]),s._v(" "),a("p",[s._v("HTTP は基本的に平文でデータをやりとりします。")]),s._v(" "),a("p",[s._v("ということは、途中でパケットキャプチャをすると、やり取りの内容を読み取ることができます。")]),s._v(" "),a("p",[s._v("もしそこにパスワード情報など見られてはいけない情報が含まれていたら...怖いですね。")]),s._v(" "),a("p",[s._v("そこで、SSL/TLS (Secure Socket Layer/Transport Layer Securityの技術)を用いて通信路の暗号化を行うHTTP over SSL いわゆるHTTPS を重要な情報のやりとりを行う際には用いるのが一般的です。")]),s._v(" "),a("p",[s._v("各種Web サーバはこのHTTPS もサポートしており、証明書とそれに対応する秘密鍵さえあれば、簡単に設定することができます。")]),s._v(" "),a("h4",{attrs:{id:"証明書と秘密鍵の用意"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#証明書と秘密鍵の用意"}},[s._v("#")]),s._v(" 証明書と秘密鍵の用意")]),s._v(" "),a("p",[s._v("HTTPS で用いる証明書は、権威ある証明局から、これは正当な証明書である、とお墨付きをもらうことで正当性が担保されています。")]),s._v(" "),a("p",[s._v("通常、証明書は以下の手順で入手します。")]),s._v(" "),a("ol",[a("li",[s._v("秘密鍵を生成する")]),s._v(" "),a("li",[s._v("秘密鍵からCSR (Certificate Signing Request) を生成する")]),s._v(" "),a("li",[s._v("CSR を証明書に提出し、審査を受け、証明局の持つ秘密鍵で署名された証明書を発行してもらう")])]),s._v(" "),a("p",[s._v("ここでは、3を簡略化して1 で生成した鍵で署名する、自己署名証明書(いわゆるオレオレ証明書)を作ります。\nこのdocker image に既にインストールされている、openssl ツールで一通りの操作を行うことができます。")]),s._v(" "),a("h5",{attrs:{id:"_1-秘密鍵を生成する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-秘密鍵を生成する"}},[s._v("#")]),s._v(" 1. 秘密鍵を生成する")]),s._v(" "),a("p",[s._v("ここではRSA の2048 bit の秘密鍵を生成します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるgenrsa はRSA 暗号の秘密鍵を生成するものとなります。")])]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /etc/nginx/ssl")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl genrsa 2048 > /etc/nginx/ssl/private.key")]),s._v("\nGenerating RSA private key, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2048")]),s._v(" bit long modulus "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" primes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v("+++++\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".+++++\ne is "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("65537")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("0x010001"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br")])]),a("h5",{attrs:{id:"_2-秘密鍵からcsr-certificate-signing-request-を生成する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-秘密鍵からcsr-certificate-signing-request-を生成する"}},[s._v("#")]),s._v(" 2. 秘密鍵からCSR (Certificate Signing Request) を生成する")]),s._v(" "),a("p",[s._v("1 で作った秘密鍵から、CSR を生成します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるreq はCSR を扱うためのものとなります。")])]),s._v(" "),a("p",[s._v("証明書で表示する情報をここで入力することになります。\n実際に発行する際は、正当性を担保したい対象であるCommon Name は特に間違わないようにしましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl req -new -sha256 -key /etc/nginx/ssl/private.key -out /etc/nginx/ssl/server.csr")]),s._v("\nYou are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields but you can leave some blank\nFor some fields there will be a default value,\nIf you enter "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'.'")]),s._v(", the field will be left blank.\n-----\nCountry Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" letter code"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("AU"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":JP\nState or Province Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("full name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Some-State"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":Tokyo\nLocality Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, city"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":Chiyoda\nOrganization Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, company"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Internet Widgits Pty Ltd"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":IIJ\nOrganizational Unit Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, section"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":TU\nCommon Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("e.g. server FQDN or YOUR name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":localhost\nEmail Address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\n\nPlease enter the following "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'extra'")]),s._v(" attributes\nto be sent with your certificate request\nA challenge password "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\nAn optional company name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br"),a("span",{staticClass:"line-number"},[s._v("18")]),a("br"),a("span",{staticClass:"line-number"},[s._v("19")]),a("br"),a("span",{staticClass:"line-number"},[s._v("20")]),a("br")])]),a("h5",{attrs:{id:"_3-署名された証明書を発行する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-署名された証明書を発行する"}},[s._v("#")]),s._v(" 3. 署名された証明書を発行する")]),s._v(" "),a("p",[s._v("1 で作った秘密鍵、2 で作ったCSR から証明書を発行します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるx509 は、証明書の標準規格を指しています。\n-req でinput がCSR であることを示し、signkey に1 で作った秘密鍵を指定することでこれで署名します。")])]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -req -in /etc/nginx/ssl/server.csr -out /etc/nginx/ssl/server.crt -signkey /etc/nginx/ssl/private.key -days 365")]),s._v("\nCertificate request self-signature ok\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("subject")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("出来上がったら、証明書の中を覗いてみましょう。text オプションでテキスト出力をすることができます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -in /etc/nginx/ssl/server.crt -text")]),s._v("\nCertificate:\n Data:\n Version: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("0x0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n Serial Number:\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("45")]),s._v(":ef:45:48:8c:89:e0:e5:38:74:f7:fc:21:32:35:eb:2b:bc:10:6b\n Signature Algorithm: sha256WithRSAEncryption\n Issuer: C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n Validity\n Not Before: Aug "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":29:36 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2022")]),s._v(" GMT\n Not After "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(":")]),s._v(" Aug "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":29:36 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2023")]),s._v(" GMT\n Subject: C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n Subject Public Key Info:\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".省略"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v("."),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br")])]),a("p",[s._v("実際に発行されたものを確認する際は、期間(Not BeforeとNot After)とSubject (CN が正しいか)に特に注意しましょう。")]),s._v(" "),a("p",[s._v("秘密鍵と証明書のペアが正しいかを確認するには、RSA のものならmodulus を比較するのが簡単です。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl rsa -in /etc/nginx/ssl/private.key -modulus -noout")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("Modulus")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("FB1908BE2B1567D1B8B7EE99DF3480CE2EDF57EC73ADD08AE2FA37A833321C84CF49D6D3F8011419BDAF8882B6E610C097D7016D173A14B7343E8D1381B8CF7FCD14CAA5717594B6F5CD586BF13EB90D2673E03B73EB25463333BD8D4384477C7910E87C8CEB2E71C83E59DD3BAC61E9B19DB97545AA9DB96DC995B01B2F96FA62CD8C777C0DA3A0377F71E0F6251CE7511964F2B4604D7F88472759C0178ECA1C7B21F9D9198166F28097A6EDF76925247119B7BEBDA73DD387607BD6320444E0242E127108C234B7F0D6CD6EB7E496747BDE7249E606BA44024E1FCC61E9ADBBE1BDABE51B342AF7DA5801AE36393E11EFFFAE60047EA7FE1E8E9A12FFF57B\n\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -in /etc/nginx/ssl/server.crt -modulus -noout")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("Modulus")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("FB1908BE2B1567D1B8B7EE99DF3480CE2EDF57EC73ADD08AE2FA37A833321C84CF49D6D3F8011419BDAF8882B6E610C097D7016D173A14B7343E8D1381B8CF7FCD14CAA5717594B6F5CD586BF13EB90D2673E03B73EB25463333BD8D4384477C7910E87C8CEB2E71C83E59DD3BAC61E9B19DB97545AA9DB96DC995B01B2F96FA62CD8C777C0DA3A0377F71E0F6251CE7511964F2B4604D7F88472759C0178ECA1C7B21F9D9198166F28097A6EDF76925247119B7BEBDA73DD387607BD6320444E0242E127108C234B7F0D6CD6EB7E496747BDE7249E606BA44024E1FCC61E9ADBBE1BDABE51B342AF7DA5801AE36393E11EFFFAE60047EA7FE1E8E9A12FFF57B\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br")])]),a("h4",{attrs:{id:"https-の設定"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#https-の設定"}},[s._v("#")]),s._v(" https の設定")]),s._v(" "),a("p",[s._v("check4 で作ったhttp で受けていたproxy をhttps でも受けられるようにしてみます。")]),s._v(" "),a("p",[a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v(" の一番下に以下を追記していきます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("server "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n listen "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("443")]),s._v(" default_server"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n listen "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("::"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":443 default_server"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n ssl on"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n ssl_certificate /etc/nginx/ssl/server.crt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n ssl_certificate_key /etc/nginx/ssl/private.key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n index index.html index.htm index.nginx-debian.html"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n server_name _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n location / "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n proxy_pass http://backend"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br")])]),a("p",[s._v("追記したら、nginx をリスタートしましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@dea1ac0e1edb:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# service nginx restart")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" ok "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" Restarting nginx: nginx.\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("443 は8443 にポートフォワードの設定が入っているため、8443 ポートにアクセスしてみましょう。\nhttps での通信となるため、URL の先頭がhttp ではなくhttps となっています。")]),s._v(" "),a("p",[a("a",{attrs:{href:"https://localhost:8443/",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://localhost:8443/"),a("OutboundLink")],1)]),s._v(" "),a("p",[s._v("今回は自己署名証明書であるため、ほとんどのブラウザは正当な証明書ではないと判断し、注意喚起の画面が表示されます。\n危険性を承知で閲覧すると、Check4 の時と同様のものが表示されます。")]),s._v(" "),a("p",[s._v("また、ブラウザ上で暗号化に使っている証明書の内容が確認できるので、確認もしてみましょう。")]),s._v(" "),a("h2",{attrs:{id:"追加課題-時間の余った人用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#追加課題-時間の余った人用"}},[s._v("#")]),s._v(" 追加課題(時間の余った人用)")]),s._v(" "),a("h3",{attrs:{id:"apache-でもhttpsを設定してみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-でもhttpsを設定してみよう"}},[s._v("#")]),s._v(" apache でもhttpsを設定してみよう")]),s._v(" "),a("ul",[a("li",[s._v("Apache でもhttps を受けられるようにしてみましょう。")]),s._v(" "),a("li",[s._v("8444 を444 にポートフォワードする設定も予め入れてあるので、444 で受ける設定を入れれば、外から8444 でアクセスできます。証明書は同じものを使い回しで構いません。")])]),s._v(" "),a("h3",{attrs:{id:"basic認証を追加してみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#basic認証を追加してみよう"}},[s._v("#")]),s._v(" Basic認証を追加してみよう")]),s._v(" "),a("ul",[a("li",[s._v("ApacheとnginxそれぞれにBasic認証を導入し、アクセスした時にユーザー名とパスワードの入力を求められるようにしてください。")]),s._v(" "),a("li",[s._v("ブラウザで動作確認ができたら、次は"),a("code",[s._v("curl")]),s._v("コマンドでアクセスしてBasic認証がどのように動作するか確認してください。")])]),s._v(" "),a("h3",{attrs:{id:"pythonアプリを動かしてみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#pythonアプリを動かしてみよう"}},[s._v("#")]),s._v(" Pythonアプリを動かしてみよう")]),s._v(" "),a("p",[s._v("Pythonで書かれたWebアプリをApache経由で動かす設定を作ってみます。\nこのdocker imageには既にpythonがインストールされています。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("python --version\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Python 3.8.17")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("Pythonで作成したWebアプリをApacheなどから実行する場合、"),a("a",{attrs:{href:"https://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface",target:"_blank",rel:"noopener noreferrer"}},[s._v("WSGI"),a("OutboundLink")],1),s._v("というインタフェース定義に従ってWebアプリを作成します。\nこれはPython側のインタフェースを規定することで、他のプログラム(今回の場合Apache)から呼び出しやすくする物です。")]),s._v(" "),a("p",[s._v("あとでやるDjangoなど主要なPythonフレームワークはこのAPIに従っているため、Djangoで作成したアプリは今回と同じ手順でApacheから実行することができます。")]),s._v(" "),a("p",[s._v("以下のようなPythonコードを"),a("code",[s._v("/var/www/html/site-80")]),s._v("以下に置いておきましょう。")]),s._v(" "),a("p",[a("code",[s._v("vim /var/www/html/site-80/app.py")])]),s._v(" "),a("div",{staticClass:"language-python line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("application")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("environ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n status "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'200 OK'")]),s._v("\n output "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("b'Hello! This is python application!'")]),s._v("\n\n response_headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-type'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'text/plain'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-Length'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("len")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("status"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" response_headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br")])]),a("p",[s._v("次にwsgiを動かすためのApache moduleをインストールします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("pip "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" mod-wsgi\n\nCollecting mod-wsgi\n Downloading mod_wsgi-4.9.4.tar.gz "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("497")]),s._v(" kB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("497.5")]),s._v("/497.5 kB "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6.1")]),s._v(" MB/s eta "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(":00:00\n Preparing metadata "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("setup.py"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(". "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("done")]),s._v("\nBuilding wheels "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" collected packages: mod-wsgi\n Building wheel "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" mod-wsgi "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("setup.py"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(". "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("done")]),s._v("\n Created wheel "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" mod-wsgi: "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("filename")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("mod_wsgi-4.9.4-cp38-cp38-linux_x86_64.whl "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("size")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("734287")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("sha256")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("b643e88dbd9659e671e2e014621153066c1061f7c385385b4ccb48b3cc453ee1\n Stored "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" directory: /root/.cache/pip/wheels/a7/96/89/a6231ee168c52f30f56065d1431e08ee24443e96b402595c85\nSuccessfully built mod-wsgi\nInstalling collected packages: mod-wsgi\nSuccessfully installed mod-wsgi-4.9.4\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br")])]),a("p",[s._v("インストールすると以下のディレクトリにsoファイルが生成されています。Apacheに読み込ませる必要があるため確認しておきましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" /usr/local/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("このファイルを読み込むように、"),a("code",[s._v("vim /etc/apache2/mods-available/wsgi.load")]),s._v("を以下のように作成します。")]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[s._v("LoadModule wsgi_module /usr/local/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("moduleを有効化しておきます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("a2enmod wsgi\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("準備が整ったのでsite-80に先ほどのPythonアプリケーションを読み込ませましょう。\n"),a("code",[s._v("vim /etc/apache2/sites-available/site-80.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("80")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-80\n WSGIScriptAlias /app /var/www/html/site-80/app.py\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br")])]),a("p",[s._v("最後にApacheをリスタートします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 restart\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[a("code",[s._v("http://localhost:8080/app")]),s._v(" にアクセスしてみてください。"),a("code",[s._v("Hello! This is python application!")]),s._v(" が表示されるでしょうか。")]),s._v(" "),a("p",[s._v("うまくいったら"),a("code",[s._v("app.py")]),s._v("を適当に変更して、Pythonが動的に実行されているのを確認してください。")]),s._v(" "),a("p",[s._v("またnginxから同様のアプリケーションを動かせるようにしてみてください。")]),s._v(" "),a("h3",{attrs:{id:"パフォーマンス測定"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#パフォーマンス測定"}},[s._v("#")]),s._v(" パフォーマンス測定")]),s._v(" "),a("p",[s._v("ApacheにはApache Benchというパフォーマンス測定ツールがついています。これを使ってMPMの違いがどのようにパフォーマンスに影響するか確認してみましょう。")]),s._v(" "),a("p",[s._v("Apache Benchは"),a("code",[s._v("ab")]),s._v("コマンドで使用できます。試しに先ほどのPythonアプリケーションのパフォーマンスを測定してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("これは"),a("code",[s._v("localhost:80/app")]),s._v("に対して合計10000リクエストを同時に100ずつ実行するコマンドです。\n実行結果には成功したリクエスト数や処理時間など、分析に使える情報が書かれています。")]),s._v(" "),a("p",[s._v("同時に1000リクエストを投げても、この時点では捌けていると思います。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("これだけでは面白くないので、pythonアプリにわざとディレイを入れてみましょう。")]),s._v(" "),a("p",[a("code",[s._v("vim /var/www/html/site-80/app.py")])]),s._v(" "),a("div",{staticClass:"language-python line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" time\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("application")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("environ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n time"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("sleep"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n status "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'200 OK'")]),s._v("\n output "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("b'Hello! Thisa is python application!'")]),s._v("\n\n response_headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-type'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'text/plain'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-Length'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("len")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("status"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" response_headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br")])]),a("p",[s._v("保存したらもう一度")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("を試してみましょう。理論上は3秒で全部のリクエストが成功するはずですがどうでしょうか。\nさらにもっと数を増やすとどうでしょうか。")]),s._v(" "),a("p",[s._v("他にも色んなことを試してみてください。")]),s._v(" "),a("ul",[a("li",[s._v("psコマンドでApacheのプロセスを確認して、リクエスト中に何が起こってるのか確認しましょう。\n"),a("ul",[a("li",[s._v("apache の再起動直後とパフォーマンス測定後の変化を見てみましょう")])])]),s._v(" "),a("li",[a("code",[s._v("/var/log/apache2/error.log")]),s._v(" を確認してみましょう")]),s._v(" "),a("li",[s._v("MPM(Multi-Processing-Module)をpreforkやworkerに変えるとどうなるでしょうか")]),s._v(" "),a("li",[s._v("MPMの設定を変えてパフォーマンスチューニングをしてみましょう")])]),s._v(" "),a("h3",{attrs:{id:"補足-mpmの変更"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#補足-mpmの変更"}},[s._v("#")]),s._v(" 補足: MPMの変更")]),s._v(" "),a("p",[s._v("現在のMPMの確認")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("apachectl -V "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" MPM\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Server MPM: event")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("MPMをpreforkに変更する。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("a2dismod mpm_event\na2enmod mpm_prefork\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 restart\napachectl -V "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" MPM\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Server MPM: prefork")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br")])]),a("credit-footer")],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{477:function(s,a,t){s.exports=t.p+"assets/img/apache-start.c57e81f7.png"},478:function(s,a,t){s.exports=t.p+"assets/img/site-80.1afd6993.png"},479:function(s,a,t){s.exports=t.p+"assets/img/site-82.9465a06d.png"},480:function(s,a,t){s.exports=t.p+"assets/img/nginx_html.ae5a2fc7.png"},481:function(s,a,t){s.exports=t.p+"assets/img/nginx-proxy.drawio.50845ff4.png"},546:function(s,a,t){"use strict";t.r(a);var n=t(10),e=Object(n.a)({},(function(){var s=this,a=s._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"apache-nginx-を触ってみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-nginx-を触ってみよう"}},[s._v("#")]),s._v(" Apache + Nginx を触ってみよう")]),s._v(" "),a("h2",{attrs:{id:"事前準備"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#事前準備"}},[s._v("#")]),s._v(" 事前準備")]),s._v(" "),a("p",[s._v("以下のように"),a("code",[s._v("docker pull")]),s._v("をしたあと、ハンズオン用のコンテナを立ち上げてログインしてください。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" pull python:3.8.17-bookworm")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("3.8.17-bookworm: Pulling from library/python\nd52e4f012db1: Pull complete\n7dd206bea61f: Pull complete\n2320f9be4a9c: Pull complete\n6e5565e0ba8d: Pull complete\nd3797e13cc41: Pull complete\n9d8ab9ac5a7d: Pull complete\n43ed38f1d568: Pull complete\n164b4060be55: Pull complete\nDigest: sha256:2ee706fa11ec6907a27f1c5116e9749ad1267336b3b0d53fc35cfba936fae32e\nStatus: Downloaded newer image for python:3.8.17-bookworm\ndocker.io/library/python:3.8.17-bookworm\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" run --rm -itd --name test-debian -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8080")]),s._v(":80 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8082")]),s._v(":82 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8088")]),s._v(":88 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8089")]),s._v(":89 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8443")]),s._v(":443 -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8444")]),s._v(":444 python:3.8.17-bookworm /bin/bash")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("a0da070e286fd52ebb323e5faff9c960014bfcd8eb1e509cb5a12daa9fb9a85e\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("$")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("exec")]),s._v(" -it test-debian /bin/bash")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("root@a0da070e286f:/#\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br")])]),a("p",[s._v("Apacheとnginxをインストールします。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("apt")]),s._v(" update")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]\nGet:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]\nGet:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]\nGet:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8906 kB]\nGet:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [4732 B]\nGet:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [48.0 kB]\nFetched 9210 kB in 3s (3184 kB/s)\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\n10 packages can be upgraded. Run 'apt list --upgradable' to see them.\n\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("apt")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" -y apache2 apache2-dev nginx "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")])])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Reading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following additional packages will be installed:\n apache2-bin apache2-data apache2-utils autopoint bsdextrautils debhelper dh-autoreconf dh-strip-nondeterminism dwz gettext gettext-base groff-base intltool-debian iproute2\n libapr1-dev libaprutil1-dbd-sqlite3 libaprutil1-dev libaprutil1-ldap libarchive-cpio-perl libarchive-zip-perl libatm1 libbpf1 libcap2-bin libdebhelper-perl\n libfile-stripnondeterminism-perl libgpm2 libldap-dev libldap2-dev liblua5.3-0 libmail-sendmail-perl libmnl0 libpam-cap libpipeline1 libsctp-dev libsctp1 libsodium23\n libsub-override-perl libsys-hostname-long-perl libuchardet0 libxtables12 man-db nginx-common po-debconf ssl-cert vim-common vim-runtime xxd\n\n~~~略~~~\n\nSetting up libapr1-dev (1.7.2-3) ...\nSetting up libaprutil1-dev (1.6.3-1) ...\nSetting up debhelper (13.11.4) ...\nSetting up apache2-dev (2.4.57-2) ...\nProcessing triggers for libc-bin (2.36-9) ...\nProcessing triggers for hicolor-icon-theme (0.17-2) ...\nroot@a0da070e286f:/#\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br"),a("span",{staticClass:"line-number"},[s._v("18")]),a("br"),a("span",{staticClass:"line-number"},[s._v("19")]),a("br"),a("span",{staticClass:"line-number"},[s._v("20")]),a("br"),a("span",{staticClass:"line-number"},[s._v("21")]),a("br"),a("span",{staticClass:"line-number"},[s._v("22")]),a("br"),a("span",{staticClass:"line-number"},[s._v("23")]),a("br"),a("span",{staticClass:"line-number"},[s._v("24")]),a("br"),a("span",{staticClass:"line-number"},[s._v("25")]),a("br"),a("span",{staticClass:"line-number"},[s._v("26")]),a("br"),a("span",{staticClass:"line-number"},[s._v("27")]),a("br"),a("span",{staticClass:"line-number"},[s._v("28")]),a("br"),a("span",{staticClass:"line-number"},[s._v("29")]),a("br"),a("span",{staticClass:"line-number"},[s._v("30")]),a("br"),a("span",{staticClass:"line-number"},[s._v("31")]),a("br"),a("span",{staticClass:"line-number"},[s._v("32")]),a("br")])]),a("p",[s._v("以下のコマンドでバージョンが表示されれば成功です。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[s._v("apache2 -v")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("Server version: Apache/2.4.57 (Debian)\nServer built: 2023-04-13T03:26:51\n")]),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[s._v("nginx -v")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("nginx version: nginx/1.22.1\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br")])]),a("h2",{attrs:{id:"webサーバー"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#webサーバー"}},[s._v("#")]),s._v(" Webサーバー")]),s._v(" "),a("p",[s._v("いわゆる「Webサーバー」とは、HTTP(Hypertext Transfer Protocol)でリクエストを受け、HTTPでレスポンスを返すソフトウェアの通称です。\n僕らがブラウザなどにURLを入力したりリンクをクリックした時、Webページが表示されるのはWebサーバーが要求したURLに対するレスポンスを返しているからです。またスマホアプリの裏で行われるサーバーとのやりとりには多くの場合HTTPが使われており、ここでもWebサーバーがゲームのデータなどをレスポンスとして返しています。")]),s._v(" "),a("p",[s._v("Webサーバのシンプルな機能は前述の通りですが、実際にはユースケースに合わせてさまざまな役割を持ちます。")]),s._v(" "),a("ul",[a("li",[s._v("HTMLやテキストファイルの配信")]),s._v(" "),a("li",[s._v("動的アプリケーションのホスティング\n"),a("ul",[a("li",[s._v("JavaやPythonやPHPなど、プログラムで生成されたレスポンスを返す")])])]),s._v(" "),a("li",[s._v("HTTP通信を別のサーバーに中継するプロキシ")]),s._v(" "),a("li",[s._v("Basic認証などによる認証処理")]),s._v(" "),a("li",[s._v("ACL(Access Control List)によるアクセス制御・不正な通信への防御")])]),s._v(" "),a("p",[s._v("簡単なWebサーバーであればどのプログラミング言語でも比較的簡単に作ることができます。\nしかし実用上はさまざまな機能をもち、セキュリティやパフォーマンスについても長年改善されてきた専用のソフトウェアが必要になり、それがいわゆる「Webサーバーソフトウェア」と呼ばれるツールです。")]),s._v(" "),a("p",[s._v("有名どころを挙げてみると")]),s._v(" "),a("ul",[a("li",[s._v("Apache HTTP Server")]),s._v(" "),a("li",[s._v("IIS")]),s._v(" "),a("li",[s._v("lighttpd")]),s._v(" "),a("li",[s._v("nginx")])]),s._v(" "),a("p",[s._v("あたりでしょうか。Linuxサーバー上で動かすのであればほぼApacheとnginxの2択になると思います。")]),s._v(" "),a("p",[s._v("また最近ではenvoyやtraefikなど、クラウドやKubernetesという文脈ではプロキシ機能に特化したソフトウェアが使われることも多くなりました。")]),s._v(" "),a("h2",{attrs:{id:"apache-と-nginx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-と-nginx"}},[s._v("#")]),s._v(" Apache と Nginx")]),s._v(" "),a("h3",{attrs:{id:"apache-http-server"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-http-server"}},[s._v("#")]),s._v(" Apache HTTP Server")]),s._v(" "),a("p",[s._v("「Apache HTTP Server」はnginxと並んで2大勢力を誇っているWebサーバソフトウェアのひとつです。 CentOSではhttpdという名前になっていたり、単にApacheと呼ばれます。")]),s._v(" "),a("p",[s._v("「Apache HTTP Server」は「Apacheソフトウェア財団」によって管理されるOSSで、20年以上の歴史を持ちます。 世界的にもっとも普及したWebサーバで、LAMP(Linux, Apache, MySQL, PHP)環境のひとつにも挙げられ、nginxと並んで2大勢力を誇ります。\n(参考: "),a("a",{attrs:{href:"https://www.netcraft.com/blog/june-2023-web-server-survey/",target:"_blank",rel:"noopener noreferrer"}},[s._v("June 2023 Web Server Survey"),a("OutboundLink")],1),s._v(")")]),s._v(" "),a("p",[s._v("正式名称は「Apache HTTP Server」ですが、歴史的経緯などからCentOSではhttpdという名前になっていたり、単にApacheと呼ばれたりします。")]),s._v(" "),a("p",[s._v("以前は大量のリクエストを受けた際にプロセスをforkできず、リクエストを捌き切れなくなる(いわゆるC10K問題)ことが問題視されました。 その際nginxをはじめとして新しいWebサーバーソフトウェアが登場しましたが、Apache自体もworkerやevent MPMといった新しい仕組みを導入し、動作も安定していることからいまだに高いシェアを占めています。")]),s._v(" "),a("h3",{attrs:{id:"nginx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nginx"}},[s._v("#")]),s._v(" nginx")]),s._v(" "),a("p",[s._v("nginxは2004年頃、当時のWebサーバーが抱えていたパフォーマンス問題(C10K問題)の解決を背景に開発が進められました。\n当時からApache 2.2は高機能で信頼性が高く、ある種成熟したソフトウェアでしたが、それに対してnginxは軽量さと高パフォーマンスに焦点をあてて開発されており、Apacheのカバーしきれないユースケースに対して力を発揮しました。")]),s._v(" "),a("p",[s._v("特に後段のサーバーにリクエストを流すリバースプロキシ・ロードバランサ機能がとても使いやすく、どちらかというと軽量なリクエストを大量に捌くのに向いています。")]),s._v(" "),a("h2",{attrs:{id:"apache-ハンズオン"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-ハンズオン"}},[s._v("#")]),s._v(" Apache ハンズオン")]),s._v(" "),a("h3",{attrs:{id:"htmlファイルの配信-check1"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#htmlファイルの配信-check1"}},[s._v("#")]),s._v(" HTMLファイルの配信(check1)")]),s._v(" "),a("p",[s._v("まずはApacheを起動しましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 start")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("ブラウザを開いて"),a("a",{attrs:{href:"http://localhost:8080",target:"_blank",rel:"noopener noreferrer"}},[s._v("localhost:8080"),a("OutboundLink")],1),s._v("にアクセスしてみてください。以下のような画面が表示されれば成功です。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(477),alt:"apache-start"}})]),s._v(" "),a("p",[s._v("表示されたページはデフォルトのHTMLファイルです。これを自分で作成したページに置き換えてみましょう。 デフォルトではDocument Rootは/var/www/html/に設定されています。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("Document RootはApacheが静的ファイルを配信するためのroot directoryです。")])]),s._v(" "),a("p",[s._v("この下にある"),a("code",[s._v("index.html")]),s._v("ファイルを自分の物に置き換えてみましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mv")]),s._v(" /var/www/html/index.html /var/www/html/_index.html")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Hello Bootcamp!!'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" /var/www/html/index.html")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("再び"),a("code",[s._v("http://localhost:8080/")]),s._v("を開くと"),a("code",[s._v("Hello Bootcamp!!")]),s._v("が表示されるのを確認してください。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[a("code",[s._v("http://localhost:8080/")]),s._v(" のようにファイル名を指定せずディレクトリ(この場合はルートディレクトリ)を指定した場合、Apacheは"),a("code",[s._v("index.html")]),s._v("を返すようにデフォルトで設定されています。\nこの設定は変更できます。")])]),s._v(" "),a("p",[s._v("Document Root配下にディレクトリを作成するとブラウザからも同様にアクセスできます。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mkdir")]),s._v(" /var/www/html/hoge")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Hello HUGA!!'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" /var/www/html/hoge/huga.txt")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("code",[s._v("http://localhost:8080/hoge/huga.txt")]),s._v(" にアクセスすると追加したファイルが表示されます。")]),s._v(" "),a("p",[s._v("アクセスログも確認してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# tail /var/log/apache2/access.log")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("h3",{attrs:{id:"virtualhost-の設定-check2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#virtualhost-の設定-check2"}},[s._v("#")]),s._v(" VirtualHost の設定(check2)")]),s._v(" "),a("p",[s._v("1つのApacheで複数のWebサイトを管理したいことがあります。異なるIPアドレスやアドレス、port番号からアクセスされた時にDocument Rootなどを切り替えたいときは"),a("code",[s._v("VirtualHost")]),s._v("を設定することで実現できます。")]),s._v(" "),a("p",[s._v("ここではport番号を"),a("code",[s._v("80")]),s._v("と"),a("code",[s._v("82")]),s._v("に分けて別々のWebサイトを設定してみます。\n(docker起動時にport forwardしているため、手元からは"),a("code",[s._v("8080")]),s._v("と"),a("code",[s._v("8082")]),s._v("からアクセスできます。)")]),s._v(" "),a("p",[s._v("まずは新しくDocument RootになるディレクトリとHTMLファイルを作成します。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /var/www/html/site-80")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /var/www/html/site-82")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# echo 'This is site 80!' > /var/www/html/site-80/index.html")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# echo 'This is site 82!' > /var/www/html/site-82/index.html")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br")])]),a("p",[s._v("次にApacheの設定をして行きます。やることは")]),s._v(" "),a("ul",[a("li",[s._v("listen portに82を追加")]),s._v(" "),a("li",[s._v("virtual host設定の追加")])]),s._v(" "),a("p",[s._v("の2つです。listen portの追加は"),a("code",[s._v("/etc/apache2/ports.conf")]),s._v("に書きましょう。\n以下のように"),a("code",[s._v("Listen 80")]),s._v(" の下に "),a("code",[s._v("Listen 82")]),s._v("の記述を追加します。")]),s._v(" "),a("div",{staticClass:"language-apache line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[s._v("# If you just change the port or add more ports here, you will likely also\n# have to change the VirtualHost statement in\n# /etc/apache2/sites-enabled/000-default.conf\n\nListen 80\nListen 82\n\n\n Listen 443\n\n\n\n Listen 443\n\n\n# vim: syntax=apache ts=4 sw=4 sts=4 sr noet\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br")])]),a("p",[s._v("VitrualHostの設定は"),a("code",[s._v("/etc/apache2/sites-available")]),s._v("の下に作成して行きます。")]),s._v(" "),a("p",[a("code",[s._v("/etc/apache2/sites-available/site-80.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("80")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-80\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[a("code",[s._v("/etc/apache2/sites-available/site-82.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("82")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-82\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("設定ファイルを作成したら"),a("code",[s._v("a2dissite")]),s._v("、"),a("code",[s._v("a2ensite")]),s._v("コマンドを使って設定を有効化しましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2dissite 000-default")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2ensite site-80")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# a2ensite site-82")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[a("code",[s._v("a2dissite")]),s._v("や"),a("code",[s._v("a2ensite")]),s._v("といったコマンドは実はapache本体の機能ではありません。"),a("code",[s._v("a2ensite")]),s._v("は"),a("code",[s._v("/etc/apache2/sites-available")]),s._v("以下のファイルのsymlinkを"),a("code",[s._v("/etc/apache2/sites-enable")]),s._v("以下に追加するだけのコマンドです。\n実際のApacheは"),a("code",[s._v("/etc/apache2/sites-enable")]),s._v("以下のコンフィグファイルをloadしているため、コマンドによってサイトが有効化されたように見えるのです。")]),s._v(" "),a("p",[s._v("CentOSなど他のディストリビューションでは、これらのコマンドが存在しないことが多いので注意してください。")])]),s._v(" "),a("p",[s._v("そしてApacheをリスタートします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# service apache2 reload")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[a("code",[s._v("localhost:8080")]),s._v("と"),a("code",[s._v("localhost:8082")]),s._v("にアクセスしてみてください。意図通りの挙動になっているでしょうか。")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("img",{attrs:{src:t(478),alt:"site-80"}})])])]),s._v(" "),a("tbody")]),s._v(" "),a("table",[a("thead",[a("tr",[a("th",[a("img",{attrs:{src:t(479),alt:"site-82"}})])])]),s._v(" "),a("tbody")]),s._v(" "),a("h2",{attrs:{id:"nginx-ハンズオン"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nginx-ハンズオン"}},[s._v("#")]),s._v(" nginx ハンズオン")]),s._v(" "),a("h3",{attrs:{id:"htmlファイルの配信-check3"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#htmlファイルの配信-check3"}},[s._v("#")]),s._v(" HTMLファイルの配信(check3)")]),s._v(" "),a("p",[s._v("次はnginxを使って同じことをしてみましょう。")]),s._v(" "),a("p",[s._v("80 portはすでにApacheが使っているため、nginxのサイトは88 portでリクエストを受け付けるようにします。")]),s._v(" "),a("div",{staticClass:"language-bash line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# vim /etc/nginx/sites-enabled/default")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("div",{staticClass:"language-nginx line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nginx"}},[a("code",[a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("88")]),s._v(" default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 80 => 88 に変更")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" [::]:88 default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 80 => 88 に変更")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("root")]),s._v(" /var/www/html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("index")]),s._v(" index.html index.htm index.nginx-debian.html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server_name")]),s._v(" _")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("location")]),s._v(" /")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("try_files")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$uri")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$uri")]),s._v("/ =404")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br")])]),a("p",[s._v("変更したらnginxを起動しましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" nginx start")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("[ ok ] Starting nginx: nginx.\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("a",{attrs:{href:"http://localhost:8088",target:"_blank",rel:"noopener noreferrer"}},[s._v("localhost:8088"),a("OutboundLink")],1),s._v(" にアクセスしてみてください。さっき作った"),a("code",[s._v("Hello Bootcamp!!")]),s._v("のHTMLが見えていれば成功です。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(480),alt:"nginx_html"}})]),s._v(" "),a("p",[s._v("アクセスログも確認してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# tail /var/log/nginx/access.log")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("h3",{attrs:{id:"ロードバランス-check4"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ロードバランス-check4"}},[s._v("#")]),s._v(" ロードバランス(check4)")]),s._v(" "),a("p",[s._v("nginxのプロキシ・ロードバランス機能を使ってみましょう。以下のような構成を作ってみます。")]),s._v(" "),a("p",[a("img",{attrs:{src:t(481),alt:"nginx_proxy"}})]),s._v(" "),a("p",[a("code",[s._v("localhost:8089")]),s._v("にアクセスすると、先ほどApacheで作ったsite-80とsite-89のどちらかにランダムでリクエストをプロキシするようにします。")]),s._v(" "),a("p",[s._v("そのための設定を"),a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v("に書いていきます。")]),s._v(" "),a("div",{staticClass:"language-nginx line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-nginx"}},[a("code",[a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("upstream")]),s._v(" backend")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")]),s._v(" localhost:80 weight=1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")]),s._v(" localhost:82 weight=1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("89")]),s._v(" default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("listen")]),s._v(" [::]:89 default_server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("index")]),s._v(" index.html index.htm index.nginx-debian.html")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("server_name")]),s._v(" _")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("location")]),s._v(" /")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token directive"}},[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("proxy_pass")]),s._v(" http://backend")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br")])]),a("p",[a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v("を作成したらnginxをリスタートしましょう。")]),s._v(" "),a("div",{staticClass:"language-shell-session line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-shell-session"}},[a("code",[a("span",{pre:!0,attrs:{class:"token command"}},[a("span",{pre:!0,attrs:{class:"token info punctuation"}},[a("span",{pre:!0,attrs:{class:"token user"}},[s._v("root@a0da070e286f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),a("span",{pre:!0,attrs:{class:"token path"}},[s._v("/")])]),a("span",{pre:!0,attrs:{class:"token shell-symbol important"}},[s._v("#")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token bash language-bash"}},[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" nginx restart")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token output"}},[s._v("[ ok ] Restarting nginx: nginx.\n")])])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[a("a",{attrs:{href:"http://localhost:8089/",target:"_blank",rel:"noopener noreferrer"}},[s._v("http://localhost:8089/"),a("OutboundLink")],1),s._v(" にアクセスしてみてください。\nsite-80とsite-82がランダムで表示されたでしょうか。")]),s._v(" "),a("h3",{attrs:{id:"https-対応-check5"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#https-対応-check5"}},[s._v("#")]),s._v(" https 対応(check5)")]),s._v(" "),a("p",[s._v("HTTP は基本的に平文でデータをやりとりします。")]),s._v(" "),a("p",[s._v("ということは、途中でパケットキャプチャをすると、やり取りの内容を読み取ることができます。")]),s._v(" "),a("p",[s._v("もしそこにパスワード情報など見られてはいけない情報が含まれていたら...怖いですね。")]),s._v(" "),a("p",[s._v("そこで、SSL/TLS (Secure Socket Layer/Transport Layer Securityの技術)を用いて通信路の暗号化を行うHTTP over SSL いわゆるHTTPS を重要な情報のやりとりを行う際には用いるのが一般的です。")]),s._v(" "),a("p",[s._v("各種Web サーバはこのHTTPS もサポートしており、証明書とそれに対応する秘密鍵さえあれば、簡単に設定することができます。")]),s._v(" "),a("h4",{attrs:{id:"証明書と秘密鍵の用意"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#証明書と秘密鍵の用意"}},[s._v("#")]),s._v(" 証明書と秘密鍵の用意")]),s._v(" "),a("p",[s._v("HTTPS で用いる証明書は、権威ある証明局から、これは正当な証明書である、とお墨付きをもらうことで正当性が担保されています。")]),s._v(" "),a("p",[s._v("通常、証明書は以下の手順で入手します。")]),s._v(" "),a("ol",[a("li",[s._v("秘密鍵を生成する")]),s._v(" "),a("li",[s._v("秘密鍵からCSR (Certificate Signing Request) を生成する")]),s._v(" "),a("li",[s._v("CSR を証明書に提出し、審査を受け、証明局の持つ秘密鍵で署名された証明書を発行してもらう")])]),s._v(" "),a("p",[s._v("ここでは、3を簡略化して1 で生成した鍵で署名する、自己署名証明書(いわゆるオレオレ証明書)を作ります。\nこのdocker image に既にインストールされている、openssl ツールで一通りの操作を行うことができます。")]),s._v(" "),a("h5",{attrs:{id:"_1-秘密鍵を生成する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-秘密鍵を生成する"}},[s._v("#")]),s._v(" 1. 秘密鍵を生成する")]),s._v(" "),a("p",[s._v("ここではRSA の2048 bit の秘密鍵を生成します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるgenrsa はRSA 暗号の秘密鍵を生成するものとなります。")])]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# mkdir /etc/nginx/ssl")]),s._v("\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl genrsa 2048 > /etc/nginx/ssl/private.key")]),s._v("\nGenerating RSA private key, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2048")]),s._v(" bit long modulus "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" primes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v("+++++\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".+++++\ne is "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("65537")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("0x010001"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br")])]),a("h5",{attrs:{id:"_2-秘密鍵からcsr-certificate-signing-request-を生成する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-秘密鍵からcsr-certificate-signing-request-を生成する"}},[s._v("#")]),s._v(" 2. 秘密鍵からCSR (Certificate Signing Request) を生成する")]),s._v(" "),a("p",[s._v("1 で作った秘密鍵から、CSR を生成します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるreq はCSR を扱うためのものとなります。")])]),s._v(" "),a("p",[s._v("証明書で表示する情報をここで入力することになります。\n実際に発行する際は、正当性を担保したい対象であるCommon Name は特に間違わないようにしましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl req -new -sha256 -key /etc/nginx/ssl/private.key -out /etc/nginx/ssl/server.csr")]),s._v("\nYou are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields but you can leave some blank\nFor some fields there will be a default value,\nIf you enter "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'.'")]),s._v(", the field will be left blank.\n-----\nCountry Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" letter code"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("AU"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":JP\nState or Province Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("full name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Some-State"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":Tokyo\nLocality Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, city"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":Chiyoda\nOrganization Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, company"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("Internet Widgits Pty Ltd"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":IIJ\nOrganizational Unit Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("eg, section"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":TU\nCommon Name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("e.g. server FQDN or YOUR name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":localhost\nEmail Address "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\n\nPlease enter the following "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'extra'")]),s._v(" attributes\nto be sent with your certificate request\nA challenge password "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\nAn optional company name "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br"),a("span",{staticClass:"line-number"},[s._v("18")]),a("br"),a("span",{staticClass:"line-number"},[s._v("19")]),a("br"),a("span",{staticClass:"line-number"},[s._v("20")]),a("br")])]),a("h5",{attrs:{id:"_3-署名された証明書を発行する"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-署名された証明書を発行する"}},[s._v("#")]),s._v(" 3. 署名された証明書を発行する")]),s._v(" "),a("p",[s._v("1 で作った秘密鍵、2 で作ったCSR から証明書を発行します。")]),s._v(" "),a("div",{staticClass:"custom-block tip"},[a("p",{staticClass:"custom-block-title"},[s._v("TIP")]),s._v(" "),a("p",[s._v("サブコマンドであるx509 は、証明書の標準規格を指しています。\n-req でinput がCSR であることを示し、signkey に1 で作った秘密鍵を指定することでこれで署名します。")])]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -req -in /etc/nginx/ssl/server.csr -out /etc/nginx/ssl/server.crt -signkey /etc/nginx/ssl/private.key -days 365")]),s._v("\nCertificate request self-signature ok\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("subject")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("出来上がったら、証明書の中を覗いてみましょう。text オプションでテキスト出力をすることができます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -in /etc/nginx/ssl/server.crt -text")]),s._v("\nCertificate:\n Data:\n Version: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("0x0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n Serial Number:\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("45")]),s._v(":ef:45:48:8c:89:e0:e5:38:74:f7:fc:21:32:35:eb:2b:bc:10:6b\n Signature Algorithm: sha256WithRSAEncryption\n Issuer: C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n Validity\n Not Before: Aug "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":29:36 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2022")]),s._v(" GMT\n Not After "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(":")]),s._v(" Aug "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":29:36 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2023")]),s._v(" GMT\n Subject: C "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" JP, ST "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Tokyo, L "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" Chiyoda, O "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" IIJ, OU "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" TU, CN "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" localhost\n Subject Public Key Info:\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".省略"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v("."),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br")])]),a("p",[s._v("実際に発行されたものを確認する際は、期間(Not BeforeとNot After)とSubject (CN が正しいか)に特に注意しましょう。")]),s._v(" "),a("p",[s._v("秘密鍵と証明書のペアが正しいかを確認するには、RSA のものならmodulus を比較するのが簡単です。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl rsa -in /etc/nginx/ssl/private.key -modulus -noout")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("Modulus")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("FB1908BE2B1567D1B8B7EE99DF3480CE2EDF57EC73ADD08AE2FA37A833321C84CF49D6D3F8011419BDAF8882B6E610C097D7016D173A14B7343E8D1381B8CF7FCD14CAA5717594B6F5CD586BF13EB90D2673E03B73EB25463333BD8D4384477C7910E87C8CEB2E71C83E59DD3BAC61E9B19DB97545AA9DB96DC995B01B2F96FA62CD8C777C0DA3A0377F71E0F6251CE7511964F2B4604D7F88472759C0178ECA1C7B21F9D9198166F28097A6EDF76925247119B7BEBDA73DD387607BD6320444E0242E127108C234B7F0D6CD6EB7E496747BDE7249E606BA44024E1FCC61E9ADBBE1BDABE51B342AF7DA5801AE36393E11EFFFAE60047EA7FE1E8E9A12FFF57B\n\nroot@a0da070e286f:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# openssl x509 -in /etc/nginx/ssl/server.crt -modulus -noout")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("Modulus")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("FB1908BE2B1567D1B8B7EE99DF3480CE2EDF57EC73ADD08AE2FA37A833321C84CF49D6D3F8011419BDAF8882B6E610C097D7016D173A14B7343E8D1381B8CF7FCD14CAA5717594B6F5CD586BF13EB90D2673E03B73EB25463333BD8D4384477C7910E87C8CEB2E71C83E59DD3BAC61E9B19DB97545AA9DB96DC995B01B2F96FA62CD8C777C0DA3A0377F71E0F6251CE7511964F2B4604D7F88472759C0178ECA1C7B21F9D9198166F28097A6EDF76925247119B7BEBDA73DD387607BD6320444E0242E127108C234B7F0D6CD6EB7E496747BDE7249E606BA44024E1FCC61E9ADBBE1BDABE51B342AF7DA5801AE36393E11EFFFAE60047EA7FE1E8E9A12FFF57B\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br")])]),a("h4",{attrs:{id:"https-の設定"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#https-の設定"}},[s._v("#")]),s._v(" https の設定")]),s._v(" "),a("p",[s._v("check4 で作ったhttp で受けていたproxy をhttps でも受けられるようにしてみます。")]),s._v(" "),a("p",[a("code",[s._v("/etc/nginx/sites-enabled/proxy")]),s._v(" の一番下に以下を追記していきます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("server "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n listen "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("443")]),s._v(" default_server"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n listen "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("::"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(":443 default_server"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n ssl on"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n ssl_certificate /etc/nginx/ssl/server.crt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n ssl_certificate_key /etc/nginx/ssl/private.key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n index index.html index.htm index.nginx-debian.html"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n server_name _"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n location / "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n proxy_pass http://backend"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br")])]),a("p",[s._v("追記したら、nginx をリスタートしましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("root@dea1ac0e1edb:/"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# service nginx restart")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" ok "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" Restarting nginx: nginx.\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("443 は8443 にポートフォワードの設定が入っているため、8443 ポートにアクセスしてみましょう。\nhttps での通信となるため、URL の先頭がhttp ではなくhttps となっています。")]),s._v(" "),a("p",[a("a",{attrs:{href:"https://localhost:8443/",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://localhost:8443/"),a("OutboundLink")],1)]),s._v(" "),a("p",[s._v("今回は自己署名証明書であるため、ほとんどのブラウザは正当な証明書ではないと判断し、注意喚起の画面が表示されます。\n危険性を承知で閲覧すると、Check4 の時と同様のものが表示されます。")]),s._v(" "),a("p",[s._v("また、ブラウザ上で暗号化に使っている証明書の内容が確認できるので、確認もしてみましょう。")]),s._v(" "),a("h2",{attrs:{id:"追加課題-時間の余った人用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#追加課題-時間の余った人用"}},[s._v("#")]),s._v(" 追加課題(時間の余った人用)")]),s._v(" "),a("h3",{attrs:{id:"apache-でもhttpsを設定してみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#apache-でもhttpsを設定してみよう"}},[s._v("#")]),s._v(" apache でもhttpsを設定してみよう")]),s._v(" "),a("ul",[a("li",[s._v("Apache でもhttps を受けられるようにしてみましょう。")]),s._v(" "),a("li",[s._v("8444 を444 にポートフォワードする設定も予め入れてあるので、444 で受ける設定を入れれば、外から8444 でアクセスできます。証明書は同じものを使い回しで構いません。")])]),s._v(" "),a("h3",{attrs:{id:"basic認証を追加してみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#basic認証を追加してみよう"}},[s._v("#")]),s._v(" Basic認証を追加してみよう")]),s._v(" "),a("ul",[a("li",[s._v("ApacheとnginxそれぞれにBasic認証を導入し、アクセスした時にユーザー名とパスワードの入力を求められるようにしてください。")]),s._v(" "),a("li",[s._v("ブラウザで動作確認ができたら、次は"),a("code",[s._v("curl")]),s._v("コマンドでアクセスしてBasic認証がどのように動作するか確認してください。")])]),s._v(" "),a("h3",{attrs:{id:"pythonアプリを動かしてみよう"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#pythonアプリを動かしてみよう"}},[s._v("#")]),s._v(" Pythonアプリを動かしてみよう")]),s._v(" "),a("p",[s._v("Pythonで書かれたWebアプリをApache経由で動かす設定を作ってみます。\nこのdocker imageには既にpythonがインストールされています。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("python --version\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Python 3.8.17")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br")])]),a("p",[s._v("Pythonで作成したWebアプリをApacheなどから実行する場合、"),a("a",{attrs:{href:"https://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface",target:"_blank",rel:"noopener noreferrer"}},[s._v("WSGI"),a("OutboundLink")],1),s._v("というインタフェース定義に従ってWebアプリを作成します。\nこれはPython側のインタフェースを規定することで、他のプログラム(今回の場合Apache)から呼び出しやすくする物です。")]),s._v(" "),a("p",[s._v("あとでやるDjangoなど主要なPythonフレームワークはこのAPIに従っているため、Djangoで作成したアプリは今回と同じ手順でApacheから実行することができます。")]),s._v(" "),a("p",[s._v("以下のようなPythonコードを"),a("code",[s._v("/var/www/html/site-80")]),s._v("以下に置いておきましょう。")]),s._v(" "),a("p",[a("code",[s._v("vim /var/www/html/site-80/app.py")])]),s._v(" "),a("div",{staticClass:"language-python line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("application")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("environ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n status "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'200 OK'")]),s._v("\n output "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("b'Hello! This is python application!'")]),s._v("\n\n response_headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-type'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'text/plain'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-Length'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("len")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("status"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" response_headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br")])]),a("p",[s._v("次にwsgiを動かすためのApache moduleをインストールします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("pip "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" mod-wsgi\n\nCollecting mod-wsgi\n Downloading mod_wsgi-4.9.4.tar.gz "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("497")]),s._v(" kB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("497.5")]),s._v("/497.5 kB "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6.1")]),s._v(" MB/s eta "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(":00:00\n Preparing metadata "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("setup.py"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(". "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("done")]),s._v("\nBuilding wheels "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" collected packages: mod-wsgi\n Building wheel "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" mod-wsgi "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("setup.py"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(". "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("done")]),s._v("\n Created wheel "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" mod-wsgi: "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("filename")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("mod_wsgi-4.9.4-cp38-cp38-linux_x86_64.whl "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("size")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("734287")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("sha256")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("b643e88dbd9659e671e2e014621153066c1061f7c385385b4ccb48b3cc453ee1\n Stored "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" directory: /root/.cache/pip/wheels/a7/96/89/a6231ee168c52f30f56065d1431e08ee24443e96b402595c85\nSuccessfully built mod-wsgi\nInstalling collected packages: mod-wsgi\nSuccessfully installed mod-wsgi-4.9.4\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br")])]),a("p",[s._v("インストールすると以下のディレクトリにsoファイルが生成されています。Apacheに読み込ませる必要があるため確認しておきましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" /usr/local/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("このファイルを読み込むように、"),a("code",[s._v("vim /etc/apache2/mods-available/wsgi.load")]),s._v("を以下のように作成します。")]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[s._v("LoadModule wsgi_module /usr/local/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("moduleを有効化しておきます。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("a2enmod wsgi\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("準備が整ったのでsite-80に先ほどのPythonアプリケーションを読み込ませましょう。\n"),a("code",[s._v("vim /etc/apache2/sites-available/site-80.conf")])]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("VirtualHost")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[s._v("*:")]),s._v("80")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n DocumentRoot /var/www/html/site-80\n WSGIScriptAlias /app /var/www/html/site-80/app.py\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br")])]),a("p",[s._v("最後にApacheをリスタートします。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 restart\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[a("code",[s._v("http://localhost:8080/app")]),s._v(" にアクセスしてみてください。"),a("code",[s._v("Hello! This is python application!")]),s._v(" が表示されるでしょうか。")]),s._v(" "),a("p",[s._v("うまくいったら"),a("code",[s._v("app.py")]),s._v("を適当に変更して、Pythonが動的に実行されているのを確認してください。")]),s._v(" "),a("p",[s._v("またnginxから同様のアプリケーションを動かせるようにしてみてください。")]),s._v(" "),a("h3",{attrs:{id:"パフォーマンス測定"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#パフォーマンス測定"}},[s._v("#")]),s._v(" パフォーマンス測定")]),s._v(" "),a("p",[s._v("ApacheにはApache Benchというパフォーマンス測定ツールがついています。これを使ってMPMの違いがどのようにパフォーマンスに影響するか確認してみましょう。")]),s._v(" "),a("p",[s._v("Apache Benchは"),a("code",[s._v("ab")]),s._v("コマンドで使用できます。試しに先ほどのPythonアプリケーションのパフォーマンスを測定してみましょう。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("これは"),a("code",[s._v("localhost:80/app")]),s._v("に対して合計10000リクエストを同時に100ずつ実行するコマンドです。\n実行結果には成功したリクエスト数や処理時間など、分析に使える情報が書かれています。")]),s._v(" "),a("p",[s._v("同時に1000リクエストを投げても、この時点では捌けていると思います。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("これだけでは面白くないので、pythonアプリにわざとディレイを入れてみましょう。")]),s._v(" "),a("p",[a("code",[s._v("vim /var/www/html/site-80/app.py")])]),s._v(" "),a("div",{staticClass:"language-python line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" time\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("def")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("application")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("environ"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(":")]),s._v("\n time"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),s._v("sleep"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\n status "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'200 OK'")]),s._v("\n output "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("b'Hello! Thisa is python application!'")]),s._v("\n\n response_headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-type'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'text/plain'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'Content-Length'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("str")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[s._v("len")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n start_response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("status"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" response_headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("return")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("output"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br")])]),a("p",[s._v("保存したらもう一度")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("ab -n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1000")]),s._v(" localhost:80/app\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br")])]),a("p",[s._v("を試してみましょう。理論上は3秒で全部のリクエストが成功するはずですがどうでしょうか。\nさらにもっと数を増やすとどうでしょうか。")]),s._v(" "),a("p",[s._v("他にも色んなことを試してみてください。")]),s._v(" "),a("ul",[a("li",[s._v("psコマンドでApacheのプロセスを確認して、リクエスト中に何が起こってるのか確認しましょう。\n"),a("ul",[a("li",[s._v("apache の再起動直後とパフォーマンス測定後の変化を見てみましょう")])])]),s._v(" "),a("li",[a("code",[s._v("/var/log/apache2/error.log")]),s._v(" を確認してみましょう")]),s._v(" "),a("li",[s._v("MPM(Multi-Processing-Module)をpreforkやworkerに変えるとどうなるでしょうか")]),s._v(" "),a("li",[s._v("MPMの設定を変えてパフォーマンスチューニングをしてみましょう")])]),s._v(" "),a("h3",{attrs:{id:"補足-mpmの変更"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#補足-mpmの変更"}},[s._v("#")]),s._v(" 補足: MPMの変更")]),s._v(" "),a("p",[s._v("現在のMPMの確認")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("apachectl -V "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" MPM\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Server MPM: event")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br")])]),a("p",[s._v("MPMをpreforkに変更する。")]),s._v(" "),a("div",{staticClass:"language-sh line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-sh"}},[a("code",[s._v("a2dismod mpm_event\na2enmod mpm_prefork\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" apache2 restart\napachectl -V "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" MPM\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#Server MPM: prefork")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br")])]),a("credit-footer")],1)}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/18.aad2b757.js b/assets/js/18.a835a4f0.js similarity index 99% rename from assets/js/18.aad2b757.js rename to assets/js/18.a835a4f0.js index 801bcfdb..245b89b9 100644 --- a/assets/js/18.aad2b757.js +++ b/assets/js/18.a835a4f0.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{392:function(s,t,a){s.exports=a.p+"assets/img/welcome.0877c950.png"},393:function(s,t){s.exports="data:image/png;base64,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"},394:function(s,t,a){s.exports=a.p+"assets/img/all_done.229f3501.png"},524:function(s,t,a){"use strict";a.r(t);var n=a(10),e=Object(n.a)({},(function(){var s=this,t=s._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h2",{attrs:{id:"下準備"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#下準備"}},[s._v("#")]),s._v(" 下準備")]),s._v(" "),t("p",[s._v("1.2 まで進めてもらえると当日はスムーズです。(DLがほとんどです。)\n1GB強あるので有線環境がお勧めです。")]),s._v(" "),t("h1",{attrs:{id:"angular-を触ってみよう"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#angular-を触ってみよう"}},[s._v("#")]),s._v(" Angular を触ってみよう")]),s._v(" "),t("h2",{attrs:{id:"angular-の紹介"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#angular-の紹介"}},[s._v("#")]),s._v(" Angular の紹介")]),s._v(" "),t("ul",[t("li",[s._v("公式(日本語) => "),t("a",{attrs:{href:"https://angular.jp/",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://angular.jp/"),t("OutboundLink")],1)])]),s._v(" "),t("p",[s._v("Angular は2016年に発表されたwebフレームワークで、googleが中心になって開発されています。")]),s._v(" "),t("p",[s._v("前身となるAngularJS(1系)は2009年に登場し、双方向バインディングなど現在のAngularに繋がる多くの概念を生み出しましたが、パフォーマンスや使い勝手の向上を目的にバージョン2.0に上がる際に1から作り直されました。")]),s._v(" "),t("p",[s._v("(現在では「Angular」と呼ぶときはバージョン2以降を、「AngularJS」と呼ぶと1系を指すので、呼び方には少し注意が必要です。)")]),s._v(" "),t("p",[s._v("特徴としては")]),s._v(" "),t("ul",[t("li",[s._v("フルスタックフレームワーク\n"),t("ul",[t("li",[s._v("Angular だけでフロントエンド開発に必要な機能が揃っている")])])]),s._v(" "),t("li",[s._v("TypeScript ベースで開発されている\n"),t("ul",[t("li",[s._v("公式ドキュメントも全て TypeScript ベース")])])]),s._v(" "),t("li",[s._v("RxJSを使ったリアクティブプログラミングが基本になっている")]),s._v(" "),t("li",[s._v("component指向")]),s._v(" "),t("li",[s._v("Angular CDKによる利用度の高い機能が半公式で提供されている")]),s._v(" "),t("li",[s._v("半年に1回のメジャーリリース")])]),s._v(" "),t("p",[s._v("などが上げられます。")]),s._v(" "),t("p",[s._v("比較的大規模なWebアプリケーションの構築に向いています。\nその理由としては、TypeScriptでの開発が強制されること。\nベストプラクティスな構成が公式から提供されているため、アプリケーションが大きくなってきても破綻しにくい。などが挙げられます。\n(大抵の必要なツールや機能が全て公式から提供されているため組み合わせに悩まなくていいのもポイント)")]),s._v(" "),t("p",[s._v("逆に記述量が多いため、小さいアプリケーションの開発ではオーバーヘッドが大きくなりがち。また学習コストも比較的高いです。")]),s._v(" "),t("h2",{attrs:{id:"_1-始めに"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-始めに"}},[s._v("#")]),s._v(" 1: 始めに")]),s._v(" "),t("p",[s._v("Angular でアプリケーションを構築する場合はほぼ必ず "),t("a",{attrs:{href:"https://cli.angular.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("angular-cli"),t("OutboundLink")],1),s._v(" というツールを利用します。これはAngular専用のCLIツールで、テンプレートコードを生成したり、開発用サーバを立ち上げたりしてくれます。\nコマンド名は「ng」です。(aNGularの略称)")]),s._v(" "),t("p",[s._v("まずはこれを使い、自動生成されるAngularアプリケーションを起動してみましょう。")]),s._v(" "),t("h3",{attrs:{id:"_1-1-docker-imageの利用方法"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-docker-imageの利用方法"}},[s._v("#")]),s._v(" 1.1: docker imageの利用方法")]),s._v(" "),t("p",[s._v("あらかじめAngularがインストールされたコンテナイメージに、ホストのディレクトリをマウントして開発を進めます。\nこうすると、ホスト側で好きなエディタを使えるので開発が楽になります。\nただし、コマンドはdockerのbashで実行する必要があります。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" pull forestsource/bootcamp-angular\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("cd")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("好きなディレクトリ ex. "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"/var/tmp/angular"')]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# MacOS, Linux")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" run --name bootcamp-angular -it --rm -v "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"'),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$(")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("pwd")]),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v(")")])]),s._v('"')]),s._v(":/app -p "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("4200")]),s._v(":4200 forestsource/bootcamp-angular "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("bash")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Windows")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("## Docker Desktopの Settings -> Resources -> FILE SHARING -> C にチェックを入れる(作業したいディレクトリがあるドライブにチェック)")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("mkdir")]),s._v(" C:"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("Users"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("%username"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("Desktop"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("bootcamp-angular\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" run --name bootcamp-angular -it --rm -v C:"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("Users"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("%username"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("Desktop"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("bootcamp-angular:/app :/app -p "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("4200")]),s._v(":4200 forestsource/bootcamp-angular "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("bash")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# コマンド実行用にシェルを起動しておく")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("docker")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("exec")]),s._v(" -it bootcamp-angular "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("bash")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br")])]),t("h3",{attrs:{id:"_1-2-angular-cliで開発環境を構築"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-angular-cliで開発環境を構築"}},[s._v("#")]),s._v(" 1.2: angular-cliで開発環境を構築")]),s._v(" "),t("p",[s._v("今回使うdocker imageにはすでにangular(angular-cli)がインストールされています。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("ng new bootcamp-angular\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# > ? Would you like to add Angular routing? (y/N) : y Angularを選択するユースケースではほぼ間違いなく使うかと思います。")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# > CSS を選択")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# > ✔ Packages installed successfully. と出力されたら成功です。")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("cd")]),s._v(" bootcamp-angular/\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Angular アプリケーションが生成されている")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" -l\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# アプリ起動")]),s._v("\nng serve --host "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br")])]),t("p",[s._v("アプリケーションの起動後 "),t("a",{attrs:{href:"http://localhost:4200",target:"_blank",rel:"noopener noreferrer"}},[s._v("http://localhost:4200"),t("OutboundLink")],1),s._v(" にアクセスするとサンプルアプリケーションが表示されます。\nAngular 開発環境の構築はこれで完了です。簡単ですね!")]),s._v(" "),t("img",{attrs:{src:a(392)}}),s._v(" "),t("h2",{attrs:{id:"_2-基本"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-基本"}},[s._v("#")]),s._v(" 2: 基本")]),s._v(" "),t("h3",{attrs:{id:"_2-1-タイトル変更"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-タイトル変更"}},[s._v("#")]),s._v(" 2.1: タイトル変更")]),s._v(" "),t("p",[t("code",[s._v("ng new")]),s._v("で生成されたアプリケーションの中身を少し見てみましょう。Angular アプリケーションのソースコードは主に "),t("code",[s._v("src/app/")]),s._v(" 以下にあります。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("246")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app-routing.module.ts\n-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app.component.css\n-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("25757")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app.component.html\n-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1089")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app.component.spec.ts\n-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("220")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app.component.ts\n-rw-r--r-- "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" root root "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("393")]),s._v(" Aug "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(":18 app.module.ts\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br")])]),t("p",[s._v("Angular はcomponent指向のフレームワークという話をしましたが、この"),t("code",[s._v(".component")]),s._v("とついているのが1つのcomponentです。この"),t("code",[s._v("app.component")]),s._v("はアプリケーション全体を束ねる親componentになります。")]),s._v(" "),t("p",[t("code",[s._v("app.component.html")]),s._v(" の中を見ると以下のようなコードがあります。\n行が長いので"),t("code",[s._v('cat app.component.html | grep "app is running!"')]),s._v("すると見つけられます。")]),s._v(" "),t("div",{staticClass:"language-html line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-html"}},[t("code",[s._v(" "),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("span")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("{{ title }} app is running!"),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[t("code",[s._v("{{}}")]),s._v("というhtmlには見慣れない記法が入っています。Angular ではこのようにhtml側に変数を展開しながらUIを作っていきます。"),t("code",[s._v("title")]),s._v("という変数は"),t("code",[s._v("app.component.ts")]),s._v("で宣言されています。")]),s._v(" "),t("div",{staticClass:"language-typescript line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-typescript"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" Component "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'@angular/core'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token decorator"}},[t("span",{pre:!0,attrs:{class:"token at operator"}},[s._v("@")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("Component")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n selector"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'app-root'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n templateUrl"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'./app.component.html'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n styleUrls"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'./app.component.css'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("export")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("AppComponent")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n title "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'bootcamp-angular'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br")])]),t("p",[s._v("色々書いてありますが、ほとんどはおまじないだと思ってもらえればいいです。重要なのは"),t("code",[s._v("title = 'bootcamp-angular';")]),s._v("で、このように"),t("code",[s._v("AppComponent")]),s._v("クラスで宣言した変数がhtml側で"),t("code",[s._v(s._s(s.title))]),s._v("として展開可能です。")]),s._v(" "),t("p",[s._v("試しにタイトルを変更してみましょう。")]),s._v(" "),t("div",{staticClass:"language-typescript line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-typescript"}},[t("code",[s._v("title "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'my-first-angular'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("と変更してファイルを保存してください。ブラウザが勝手に更新されてタイトルが変更されます。")]),s._v(" "),t("h2",{attrs:{id:"_2-2-component作成"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-component作成"}},[s._v("#")]),s._v(" 2.2: component作成")]),s._v(" "),t("p",[s._v("次はcomponentを作ってみましょう。angular-cliには雛形を自動的に生成してくれる機能があります。以下のコマンドを実行してください。")]),s._v(" "),t("div",{staticClass:"language-bash line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("ng generate component peoples\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#> CREATE src/app/peoples/peoples.component.css (0 bytes)")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#> CREATE src/app/peoples/peoples.component.html (22 bytes)")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#> CREATE src/app/peoples/peoples.component.spec.ts (635 bytes)")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#> CREATE src/app/peoples/peoples.component.ts (279 bytes)")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#> UPDATE src/app/app.module.ts (479 bytes)")]),s._v("\n\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br")])]),t("p",[s._v("すると"),t("code",[s._v("src/app/peoples/")]),s._v("以下にcomponentの雛形が生成されます。ただし作っただけでは表示されません。componentを表示するには以下の2通りの方法があります。")]),s._v(" "),t("ul",[t("li",[s._v("既存のcomponentに埋め込んで表示する")]),s._v(" "),t("li",[s._v("ルーティングを登録して別ページとして表示する")])]),s._v(" "),t("h2",{attrs:{id:"_2-3-ルーティング作成"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-ルーティング作成"}},[s._v("#")]),s._v(" 2.3: ルーティング作成")]),s._v(" "),t("p",[s._v("ここではルーティングを登録してみましょう。"),t("code",[s._v("src/app/app-routing.module.ts")]),s._v("を以下のように変更してください。")]),s._v(" "),t("div",{staticClass:"language-typescript line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-typescript"}},[t("code",[t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" NgModule "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'@angular/core'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" Routes"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" RouterModule "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'@angular/router'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("import")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" PeoplesComponent "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("from")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'./peoples/peoples.component'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("const")]),s._v(" routes"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" Routes "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" path"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("'peoples'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" component"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" PeoplesComponent"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token decorator"}},[t("span",{pre:!0,attrs:{class:"token at operator"}},[s._v("@")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("NgModule")])]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n imports"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("RouterModule"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(".")]),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("forRoot")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("routes"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n exports"),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("RouterModule"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("export")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("class")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token class-name"}},[s._v("AppRoutingModule")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br"),t("span",{staticClass:"line-number"},[s._v("2")]),t("br"),t("span",{staticClass:"line-number"},[s._v("3")]),t("br"),t("span",{staticClass:"line-number"},[s._v("4")]),t("br"),t("span",{staticClass:"line-number"},[s._v("5")]),t("br"),t("span",{staticClass:"line-number"},[s._v("6")]),t("br"),t("span",{staticClass:"line-number"},[s._v("7")]),t("br"),t("span",{staticClass:"line-number"},[s._v("8")]),t("br"),t("span",{staticClass:"line-number"},[s._v("9")]),t("br"),t("span",{staticClass:"line-number"},[s._v("10")]),t("br"),t("span",{staticClass:"line-number"},[s._v("11")]),t("br"),t("span",{staticClass:"line-number"},[s._v("12")]),t("br"),t("span",{staticClass:"line-number"},[s._v("13")]),t("br")])]),t("p",[s._v("これは"),t("code",[s._v("/peoples")]),s._v("というパスにアクセスした時"),t("code",[s._v("PeoplesComponent")]),s._v("の内容を表示するという設定です。\n"),t("code",[s._v("PeoplesComponent")]),s._v("の表示位置は"),t("code",[s._v("src/app/app.component.html")]),s._v("にある")]),s._v(" "),t("div",{staticClass:"language-html line-numbers-mode"},[t("pre",{pre:!0,attrs:{class:"language-html"}},[t("code",[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("router-outlet")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token tag"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),t("div",{staticClass:"line-numbers-wrapper"},[t("span",{staticClass:"line-number"},[s._v("1")]),t("br")])]),t("p",[s._v("の部分に表示されます。試しに "),t("a",{attrs:{href:"http://192.168.20.10:4200/peoples",target:"_blank",rel:"noopener noreferrer"}},[s._v("http://192.168.20.10:4200/peoples"),t("OutboundLink")],1),s._v(" にアクセスしてみてください。下の方に"),t("code",[s._v("peoples works!")]),s._v("が表示されていれば成功です。")]),s._v(" "),t("p",[s._v("このようにAngularなどモダンなフレームワークはページ遷移を再現するための「ルーター」と呼ばれる機能を提供しています。")]),s._v(" "),t("p",[s._v("ついでに邪魔なので、"),t("code",[s._v("src/app/app.component.html")]),s._v("には"),t("code",[s._v("peoples")]),s._v("へのリンクだけを残して綺麗にしてしまいましょう。\nこの時 "),t("code",[s._v("