Let's Encryptを使ったHTTPS化

HTTPS化

このブログはhexoを使って表示しています。
以前HTTPSにしないとサイトの評価が上がらないと言われていたので、HTTPSにしようと思います。
できるだけ管理に手間をかけたくないので、Let’s Encryptを利用しようと思います。

Let’s Encryptについて

恥ずかしながらLet’s Encryptを利用するのは今回が初めてです。なので、本家のサイトをまず見てみます。
ドキュメントを上から読んでいくと、以下のことがわかります。

  • ACMEプロトコルを利用している
  • 証明書を設置するサーバにSSHログインできる場合、CertbotというACMEクライアントを利用する
  • ドメイン検証 (Domain Validation; DV) 型の証明書
  • 無料で利用できる

想定としてはリバースプロキシとしてnginxを動かして、フォワード先をhexoとします。
では早速進めていきたいと思います。

Certbot

Let’s EncryptのACMEクライアント実装というページでもCertbotをおすすめしています。とりあえずこれをインストールしてみようと思います。
Certbotのページにいくと、My HTTP Website is runningという表示があります。そのセレクトボックスに自分の環境のHTTPサーバ、OSを指定します。

AmazonLinux2のベースはなに?

OSを選ぼうとしたらAmazonLinux2の文字はありませんでした。そう言われるとAmazonLinux2のベースのOSはなんだろう?と思いました。
ググってみるとCentOS/RHEL 7のようです。yumが利用できるのでRedHat系かとは思っていましたが、RHEL7ベースのようなのでそれを選択しました。

Certbotのインストール

SoftwareNginxSystemCentOS/RHEL 7を選択すると、ページ下にインストール方法が表示されれます。
その手順通りに進めていきます。

サーバーにログインします

ログインします

EPELリポジトリを有効にします

今有効になっているリポジトリ一覧を見てみます。

1
2
3
4
5
6
7
8
9
10
$ sudo yum repolist all
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
リポジトリー ID リポジトリー名 状態
!amzn2-core/2/x86_64 Amazon Linux 2 core repository 有効: 19,545
amzn2-core-debuginfo/2/x86_64 Amazon Linux 2 core repository - debugin 無効
amzn2-core-source/2 Amazon Linux 2 core repository - source 無効
!amzn2extra-docker/2/x86_64 Amazon Extras repo for docker 有効: 24
amzn2extra-docker-debuginfo/2/x86_64 Amazon Extras debuginfo repo for docker 無効
amzn2extra-docker-source/2 Amazon Extras source repo for docker 無効
repolist: 19,569

有効になっていないようなので有効にします。
有効にする方法はこちらに記載されていました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
epel-release-latest-7.noarch.rpm | 15 kB 00:00:00
/var/tmp/yum-root-HHwmTy/epel-release-latest-7.noarch.rpm を調べています: epel-release-7-12.noarch
/var/tmp/yum-root-HHwmTy/epel-release-latest-7.noarch.rpm をインストール済みとして設定しています
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ epel-release.noarch 0:7-12 を インストール
--> 依存性解決を終了しました。
amzn2-core/2/x86_64 | 2.4 kB 00:00:00
amzn2extra-docker/2/x86_64 | 1.8 kB 00:00:00

依存性を解決しました

==========================================================================================
Package アーキテクチャー
バージョン リポジトリー 容量
==========================================================================================
インストール中:
epel-release noarch 7-12 /epel-release-latest-7.noarch 24 k

トランザクションの要約
==========================================================================================
インストール 1 パッケージ

合計容量: 24 k
インストール容量: 24 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
インストール中 : epel-release-7-12.noarch 1/1
検証中 : epel-release-7-12.noarch 1/1

インストール:
epel-release.noarch 0:7-12

完了しました!

次にepelを有効にします。

1
2
3
4
5
6
$ sudo yum-config-manager --enable epel
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
======================================= repo: epel =======================================
[epel]
async = True
(省略)

有効になったかを確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo yum repolist all
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
192 packages excluded due to repository priority protections
リポジトリー ID リポジトリー名 状態
!amzn2-core/2/x86_64 Amazon Linux 2 core repository 有効: 19,545
amzn2-core-debuginfo/2/x86_64 Amazon Linux 2 core repository - deb 無効
amzn2-core-source/2 Amazon Linux 2 core repository - sou 無効
amzn2extra-docker/2/x86_64 Amazon Extras repo for docker 有効: 24
amzn2extra-docker-debuginfo/2/x86_64 Amazon Extras debuginfo repo for doc 無効
amzn2extra-docker-source/2 Amazon Extras source repo for docker 無効
epel/x86_64 Extra Packages for Enterprise Linux 有効: 13,061+192
epel-debuginfo/x86_64 Extra Packages for Enterprise Linux 無効
epel-source/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing-debuginfo/x86_64 Extra Packages for Enterprise Linux 無効
epel-testing-source/x86_64 Extra Packages for Enterprise Linux 無効
repolist: 32,630

有効になっていますね。epelのその他のリポジトリも有効にすれば利用できるようになっていました。

optional channelを有効にする

パッケージyum-utilsはインストール済だったので、有効にするコマンドのみ実行します。
記載のコマンドのREGIONはap-northeast-1に置き換えて実行してみます。

1
2
$ sudo yum-config-manager --enable rhui-ap-northeast-1-rhel-server-extras rhui-ap-northeast-1-rhel-server-optional
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd

特に変化はなさそうですが、一旦次に進んでみます。

Certbotをインストール

次のコマンドを実行します。

1
2
3
$ sudo yum install certbot python2-certbot-nginx
(省略)
完了しました!

Certbotの実行

CertbotがNginxの設定を書き換えると書いてあります。
まだNginxの準備ができていないので、そちらを行います。

1
2
3
$ sudo yum install nginx.x86_64
(省略)
完了しました!

Nginxのインストールが完了したので、hexoへリバースプロキシをする設定を追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi /etc/nginx/conf.d/hexo.conf
server {
server_name book-reviews.blog;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location / {
proxy_pass http://localhost:8080/;
}
}

hexoのポートも80から8080に変更しています。

Nginxを起動しておかないとCertbotの実行でエラーが出るので起動しておきます。

1
$ sudo systemctl start nginx

準備が整ったのでCertbotを実行します。

1
2
3
4
5
6
7
8
9
10
$ sudo certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

設定ファイルから自動的にドメインを認識してくれるので該当するドメインを選択します。

1
2
3
4
5
6
7
8
9
10
11
(中略)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
server {
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/hexo.conf

HTTPのアクセスをHTTPSへリダイレクトするかどうか聞かれるので、リダイレクトするを選びました。nginxの設定に301redirectが追記されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://book-reviews.blog

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=book-reviews.blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
(中略)
Your cert will expire on 2020-08-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

ということで無事インストールが終わりました。

1
2
3
Your cert will expire on 2020-08-04. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option.

ということなので、2020年8月4日には有効期限が切れてしまうようです。またその際にcertonlyオプションをつけて実行します。

HTTPSアクセスを試す

今このページもHTTPSで表示されていると思いますが、無事表示されました!
HTTPアクセスもちゃんとリダイレクトされます!

まとめ

初めてLet’s EncryptでHTTPS化しましたが、とても楽でした!Certbotのおかげだと思います!
ここには記載しなかったですが、Hexoのsystemdでの起動でちょっとつまずきました。
この点については近いうちに記載したいと思います。

※追記 こちらに記載しました。

15Stepで習得 Dockerから入るKubernetes その5

ロールアウト・ロールバック

ロールアウト機能

ロールアウトとは、アプリケーションコンテナの更新
サービスが止まらないよう、古いPodと新しいPodを入れ替えることが可能

例)nginxの設定を変更する
手順

  1. nginxの設定を変更
  2. 新しいコンテナイメージとしてビルド
  3. コンテナイメージをリポジトリへ登録する
  4. マニフェストで指定されているコンテナイメージ新しいコンテナイメージに変更する
  5. ロールアウト

マニフェストファイルの作成

変更前のマニフェストをnginx-deployment2.yml、変更後のマニフェストをnignx-deployment3.ymlとする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat nginx-deployment2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.16

nginxのバージョンは1.16

変更後

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat nginx-deployment3.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.17

違いは

1
2
3
4
5
6
7
8
9
$ diff -u nginx-deployment2.yml nginx-deployment3.yml
--- nginx-deployment2.yml 2020-03-04 21:39:06.000000000 +0900
+++ nginx-deployment3.yml 2020-03-04 21:40:14.000000000 +0900
@@ -14,4 +14,4 @@
spec:
containers:
- name: nginx
- image: nginx:1.16
+ image: nginx:1.17

のようにバージョンのみ

マニフェストの適用

まずはnginx-deployment2.ymlから

1
2
3
4
5
6
7
8
9
$ kubectl apply -f nginx-deployment2.yml
deployment.apps/web-deploy created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
web-deploy-866f97c649-788hf 1/1 Running 0 6s
web-deploy-866f97c649-8hsr8 1/1 Running 0 6s
web-deploy-866f97c649-kfxmg 1/1 Running 0 6s
web-deploy-866f97c649-pqrbf 1/1 Running 0 6s
web-deploy-866f97c649-vrm6r 1/1 Running 0 6s

起動したことがわかる
詳細に見る場合はkubectl describeを利用する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.16
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-866f97c649 (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6s deployment-controller Scaled up replica set web-deploy-866f97c649 to 5

nginxのimageは1.16

次にnginx-deployment3.ymlを適用する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ kubectl apply -f nginx-deployment3.yml
deployment.apps/web-deploy configured
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 0/1 ContainerCreating 0 4s
web-deploy-85477dddcd-4z7bw 0/1 ContainerCreating 0 4s
web-deploy-85477dddcd-crs96 0/1 ContainerCreating 0 4s
web-deploy-866f97c649-5z7r9 0/1 Terminating 0 2m48s
web-deploy-866f97c649-65fpv 1/1 Running 0 2m48s
web-deploy-866f97c649-7j7m6 1/1 Running 0 2m48s
web-deploy-866f97c649-nsw5d 1/1 Running 0 2m48s
web-deploy-866f97c649-vkwxd 1/1 Running 0 2m48s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 1/1 Running 0 34s
web-deploy-85477dddcd-4z7bw 1/1 Running 0 34s
web-deploy-85477dddcd-5plrj 1/1 Running 0 23s
web-deploy-85477dddcd-848ww 1/1 Running 0 24s
web-deploy-85477dddcd-crs96 1/1 Running 0 34s

数十秒で入れ替わったことがわかる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 2
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.17
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-85477dddcd (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 4m24s deployment-controller Scaled up replica set web-deploy-866f97c649 to 5
Normal ScalingReplicaSet 100s deployment-controller Scaled up replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 100s deployment-controller Scaled down replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 100s deployment-controller Scaled up replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 90s deployment-controller Scaled down replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 90s deployment-controller Scaled up replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 89s deployment-controller Scaled down replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 89s deployment-controller Scaled up replica set web-deploy-85477dddcd to 5
Normal ScalingReplicaSet 88s deployment-controller Scaled down replica set web-deploy-866f97c649 to 1
Normal ScalingReplicaSet 85s deployment-controller (combined from similar events): Scaled down replica set web-deploy-866f97c649 to 0

nginxのimageが1.17になっているのがわかる。またEventsにロールアウトの履歴が残っていることがわかる

ロールバック機能

Kubernetesにおけるロールバック機能は「ロールアウト前の古いコンテナへ戻すためにPodを入れ替えること」をさす

ロールバックコマンド

以下の1行で実行できる

1
kubectl rollout undo deployment デプロイメント名

実際に実行してみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ kubectl rollout undo deployment web-deploy
deployment.apps/web-deploy rolled back
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4hzs9 0/1 Terminating 0 11m
web-deploy-85477dddcd-4z7bw 1/1 Running 0 11m
web-deploy-85477dddcd-5plrj 1/1 Terminating 0 11m
web-deploy-85477dddcd-848ww 1/1 Terminating 0 11m
web-deploy-85477dddcd-crs96 1/1 Terminating 0 11m
web-deploy-866f97c649-2sfv5 0/1 ContainerCreating 0 2s
web-deploy-866f97c649-nwv7d 0/1 ContainerCreating 0 2s
web-deploy-866f97c649-qhvdr 1/1 Running 0 4s
web-deploy-866f97c649-xskvq 1/1 Running 0 5s
web-deploy-866f97c649-xw4zq 1/1 Running 0 5s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-85477dddcd-4z7bw 1/1 Terminating 0 11m
web-deploy-866f97c649-2sfv5 1/1 Running 0 7s
web-deploy-866f97c649-nwv7d 1/1 Running 0 7s
web-deploy-866f97c649-qhvdr 1/1 Running 0 9s
web-deploy-866f97c649-xskvq 1/1 Running 0 10s
web-deploy-866f97c649-xw4zq 1/1 Running 0 10s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-deploy-866f97c649-2sfv5 1/1 Running 0 12s
web-deploy-866f97c649-nwv7d 1/1 Running 0 12s
web-deploy-866f97c649-qhvdr 1/1 Running 0 14s
web-deploy-866f97c649-xskvq 1/1 Running 0 15s
web-deploy-866f97c649-xw4zq 1/1 Running 0 15s

実際に動いているバージョンを確認する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ kubectl describe deployment web-deploy
Name: web-deploy
Namespace: default
CreationTimestamp: Mon, 09 Mar 2020 21:46:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 3
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"web-deploy","namespace":"default"},"spec":{"replicas":5,"...
Selector: app=web
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.16
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-deploy-866f97c649 (5/5 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 12m deployment-controller Scaled down replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 12m deployment-controller Scaled down replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set web-deploy-85477dddcd to 5
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set web-deploy-866f97c649 to 1
Normal ScalingReplicaSet 11m deployment-controller (combined from similar events): Scaled down replica set web-deploy-866f97c649 to 0
Normal ScalingReplicaSet 32s deployment-controller Scaled up replica set web-deploy-866f97c649 to 2
Normal ScalingReplicaSet 32s deployment-controller Scaled down replica set web-deploy-85477dddcd to 4
Normal ScalingReplicaSet 31s deployment-controller Scaled up replica set web-deploy-866f97c649 to 3
Normal ScalingReplicaSet 29s (x2 over 14m) deployment-controller Scaled up replica set web-deploy-866f97c649 to 5
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 3
Normal ScalingReplicaSet 29s deployment-controller Scaled up replica set web-deploy-866f97c649 to 4
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 2
Normal ScalingReplicaSet 29s deployment-controller Scaled down replica set web-deploy-85477dddcd to 1
Normal ScalingReplicaSet 23s deployment-controller Scaled down replica set web-deploy-85477dddcd to 0

1.16に戻っていることがわかる

ロールアウト、ロールバック機能はサービスを停止することなくリリースを行うことができる
実際にアクセスできるサービスを立ち上げないと実感がわかないので、次はServiceについて調べてみる

15Stepで習得 Dockerから入るKubernetes その4

Deploymentの概要

DeploymentはReplicaSetを管理する仕組み
ReplicaSetはPodを管理し、Pod内にコンテナが存在する

Deploymentのマニフェストファイル

シンプルな例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest

ポイント

  • Podの稼働数が3 replicas: 3
  • matchLabelsapp: web を指定
    • templatelabelsは先ほどselector内で指定したapp: webと同じにする
  • specに関してはPodのspecと同じ

Deploymentのマニフェストファイルの実行

実行する

1
2
$ kubectl apply -f nginx-deployment.yml
deployment.apps/web-deploy created

各情報をみてみる

1
2
3
4
5
6
7
8
9
10
11
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
web-deploy 3/3 3 3 24m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
web-deploy-654cd6d4d8 3 3 3 27m
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 28m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 28m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 28m 172.17.0.4 minikube <none> <none>

replicasetを増やしてみる

マニフェストファイルのreplicasの値を増減することでReplicaSetの数を調整でき、スケールすることができる
これとは別でCPU使用率と連動して動的にReplicaSetを数を増やすことができるオートスケール機能がある

スタティックな変更

マニフェストをreplicas: 5にしてみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deploy
spec:
replicas: 5
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest

適用する

1
2
$ kubectl apply -f nginx-deployment.yml
deployment.apps/web-deploy configured

実行時の表示はconfigured
起動したPodを確認してみる

1
2
3
4
5
6
7
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 11s 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 37m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 37m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 11s 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 37m 172.17.0.4 minikube <none> <none>

既存の3つのPodに加えて、新しく2つのPodが起動しているのがわかる

コマンドラインでの変更

kubectl scaleを実行することでPodの数を調整できる
現状確認

1
2
3
4
5
6
7
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 9m53s 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 47m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 47m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 9m53s 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 47m 172.17.0.4 minikube <none> <none>

5コ
10コにする

1
2
$ kubectl scale --replicas=10 deployment.apps/web-deploy
deployment.apps/web-deploy scaled

メッセージはscaled
確認する

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-deploy-654cd6d4d8-6dg2c 1/1 Running 0 13m 172.17.0.7 minikube <none> <none>
web-deploy-654cd6d4d8-j2cjg 1/1 Running 0 50m 172.17.0.6 minikube <none> <none>
web-deploy-654cd6d4d8-jw5z4 1/1 Running 0 35s 172.17.0.11 minikube <none> <none>
web-deploy-654cd6d4d8-n274r 1/1 Running 0 50m 172.17.0.5 minikube <none> <none>
web-deploy-654cd6d4d8-nwv8f 1/1 Running 0 35s 172.17.0.10 minikube <none> <none>
web-deploy-654cd6d4d8-pfp5n 1/1 Running 0 35s 172.17.0.9 minikube <none> <none>
web-deploy-654cd6d4d8-rnfpw 1/1 Running 0 35s 172.17.0.13 minikube <none> <none>
web-deploy-654cd6d4d8-tdwt4 1/1 Running 0 13m 172.17.0.8 minikube <none> <none>
web-deploy-654cd6d4d8-tgs6w 1/1 Running 0 50m 172.17.0.4 minikube <none> <none>
web-deploy-654cd6d4d8-wgltb 1/1 Running 0 35s 172.17.0.12 minikube <none> <none>

既存の5コに加えて新規5コが追加されたことがわかる

次回はPodの入替を行なってみる

15Stepで習得 Dockerから入るKubernetes その3

マニフェストファイル

今回はマニフェストファイルを作成してアプリケーションを記述し、実行する

マニフェストファイルの作成

Podのマニフェストファイル(nginxのサンプル)を作成

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest

マニフェストファイルの記述方法は
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/
にあるがよくわからない
kindPodにすると、Podのマニフェストファイルとなる。

マニフェストファイルの適用

以下のコマンドで適用する

1
$ kubectl apply -f 作成したマニフェストファイル

実際に作成したファイルはkubernetes/nginx-pod.ymlなので以下を実行する

1
2
3
4
5
$ kubectl apply -f kubernetes/nginx-pod.yml
pod/nginx created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 7s

クラスタネットワーク上のPodのIPアドレスを表示するには、-o wide オプションを追加する

1
2
3
$ kubectl get pod nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 52s 172.17.0.4 minikube <none> <none>

表示されているIPアドレスに80番でアクセスしてみると、ERR_SOCKET_NOT_CONNECTEDが返ってくる
クラスタネットワーク上のPodにクラスタネットワーク外からアクセスするためにはServiceを利用する必要がある
Serviceはクラスタネットワークのロードバランサ的な存在
今回はServiceなしで動作確認するために、クラスタネットワーク内にPodを作成してテストする

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ kubectl run busybox --image=busybox --restart=Never --rm -it sh
If you don't see a command prompt, try pressing enter.

/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:05
inet addr:172.17.0.5 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

/ # wget http://172.17.0.4
Connecting to 172.17.0.4 (172.17.0.4:80)
saving to 'index.html'
index.html 100% |********************************| 612 0:00:00 ETA
'index.html' saved
/ # more index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
/ #

nginxが動作していることが確認できた

次はDeploymentの作成をマニフェストファイルで行う

15Stepで習得 Dockerから入るKubernetes その2

Kubernetes hello-world

前回の作業でローカルに環境が構築できたので、hello-worldのイメージを利用していろいろ試してみる

Podの起動

Pod単体で起動する場合は--restart=Neverオプションをつける
また最初は-itをつけてインタラクティブに実行してみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ kubectl run hello-world --image=hello-world -it --restart=Never


Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

実行できていることがわかる
Podの一覧を取得してみると

1
2
3
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-world 0/1 Completed 0 54s

実行完了したPodが残っているのがわかる

–rmオプション

dockerと同じ(-itも一緒だった)で--rmで実行後に自動削除してくれる

1
2
$ kubectl run hello-world --image=hello-world -it --restart=Never --rm
Error from server (AlreadyExists): pods "hello-world" already exists

先ほど起動したPodを削除していなかったので削除する

1
2
3
4
$ kubectl delete pod hello-world
pod "hello-world" deleted
$ kubectl get pod
No resources found in default namespace.

再度実行

1
2
3
4
5
6
$ kubectl run hello-world --image=hello-world -it --restart=Never --rm

Hello from Docker!
(省略)
$ kubectl get pod
No resources found in default namespace.

実行後削除されているのがわかる

バックグラウンド実行

-itなしで実行することでバックグラウンドでの実行となる

1
2
$ kubectl run hello-world --image=hello-world --restart=Never
pod/hello-world created

出力(log)を確認する

1
2
3
4
5
6
7
8
9
$ kubectl logs hello-world

Hello from Docker!
(省略)
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-world 0/1 Completed 0 59s
$ kubectl delete pod hello-world
pod "hello-world" deleted

Deployment経由でPodを起動

今までは--restart=Neverオプションをつけてきたが、デフォルトは--restart=Alwaysである
その場合はDeployment経由でReplicaSetが起動し、RecplicaSetがPodを管理する

1
2
3
$ kubectl run hello-world --image=hello-world
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/hello-world created

DEPRECATEDのメッセージが出てしまったが、deployment.apps/hello-world createdとのことなので実行はできているっぽい
Use kubectl run --generator=run-pod/v1 or kubectl create instead.とのことなので今後は
kubectl create deployment --image hello-world hello-worldを利用する

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/hello-world-664fd677b8-gmm2f 0/1 Completed 3 62s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-world 0/1 1 0 62s

NAME DESIRED CURRENT READY AGE
replicaset.apps/hello-world-664fd677b8 1 1 0 62s

試しにPodを削除してみる

1
2
$ kubectl delete pod hello-world-664fd677b8-gmm2f
pod "hello-world-664fd677b8-gmm2f" deleted

しかし、ReplicaSetが再度起動する

1
2
3
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-world-664fd677b8-6n967 0/1 CrashLoopBackOff 2 43s

命名規則

Deployment

deployment.apps/hello-worldとなっていてdeployment.apps/の後ろに指定した名前が追加される

ReplicaSet

replicaset.apps/hello-world-664fd677b8となっていて、replicaset.apps/の後ろに指定した名前とハッシュ文字列が追加される

Pod

pod/hello-world-664fd677b8-gmm2fとなっていて、pod/の後ろに指定した名前とハッシュ文字列が追加される

Deploymentの停止

1
2
3
4
5
6
7
8
$ kubectl delete deployment hello-world
deployment.apps "hello-world" deleted
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/hello-world-664fd677b8-6n967 0/1 Terminating 7 13m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h

Podは停止に少し時間がかかるが、少し待てば削除される

1
2
3
$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10h

次はマニフェストを書いて意味のあるアプリケーションを構築しようと思う

15Stepで習得 Dockerから入るKubernetes その1

Kubernetes入門

Kubernetesを始めるにあたり、書籍を購入。
docker desktopのKubernetesでEnable Kubernetesにチェックを入れると使えるようになると記載されているものが多いがやってみたところうまくいかない
こちらではマネージドサービスの利用を強く推奨している

試したこと

  • Enable Kubernetesにチェックを入れる
  • Show system containers (advanced) にチェックを入れる
  • Applyする
1
2
3
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: Service Unavailable

Serverが反応しない

Show system containers (advanced) にチェックを入れると、いくつかコンテナが起動しているようにみえる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c0adb0a59ec eb516548c180 "/coredns -conf /etc…" 8 seconds ago Up 8 seconds k8s_coredns_coredns-5c98db65d4-ccpgw_kube-system_bca3360b-c620-4dc1-adbb-4f4f72e256f7_0
09027b92a495 eb516548c180 "/coredns -conf /etc…" 8 seconds ago Up 8 seconds k8s_coredns_coredns-5c98db65d4-wnz9s_kube-system_012b9fa8-c63d-49cb-9a92-4c0116283030_0
af28dfeeeab0 cbd7f21fec99 "/usr/local/bin/kube…" 9 seconds ago Up 8 seconds k8s_kube-proxy_kube-proxy-js5n2_kube-system_0f046985-bdd9-4c87-bf04-b8bc86520fb6_0
6f021151faee k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 8 seconds k8s_POD_coredns-5c98db65d4-wnz9s_kube-system_012b9fa8-c63d-49cb-9a92-4c0116283030_0
4be2180c3476 k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 8 seconds k8s_POD_coredns-5c98db65d4-ccpgw_kube-system_bca3360b-c620-4dc1-adbb-4f4f72e256f7_0
d37faa0633fe k8s.gcr.io/pause:3.1 "/pause" 9 seconds ago Up 9 seconds k8s_POD_kube-proxy-js5n2_kube-system_0f046985-bdd9-4c87-bf04-b8bc86520fb6_0
9faf284de0a2 fab2dded59dd "kube-scheduler --bi…" 23 seconds ago Up 23 seconds k8s_kube-scheduler_kube-scheduler-docker-desktop_kube-system_131c3f63daec7c0750818f64a2f75d20_0
adbe6374475a e534b1952a0d "kube-apiserver --ad…" 23 seconds ago Up 23 seconds k8s_kube-apiserver_kube-apiserver-docker-desktop_kube-system_556b996466155d7ad37d896897208f67_0
d063399d4feb 1399a72fa1a9 "kube-controller-man…" 23 seconds ago Up 23 seconds k8s_kube-controller-manager_kube-controller-manager-docker-desktop_kube-system_b2850863d2a1ddaac8ed962e6881584c_0
a6501f7001f5 2c4adeb21b4f "etcd --advertise-cl…" 23 seconds ago Up 23 seconds k8s_etcd_etcd-docker-desktop_kube-system_f132e1c85abd4953a304d1c65d9d74f9_0
61b6078a415c k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-scheduler-docker-desktop_kube-system_131c3f63daec7c0750818f64a2f75d20_0
036ba80a78f6 k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-controller-manager-docker-desktop_kube-system_b2850863d2a1ddaac8ed962e6881584c_0
c1f2ca81a768 k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_kube-apiserver-docker-desktop_kube-system_556b996466155d7ad37d896897208f67_0
a832aab318ac k8s.gcr.io/pause:3.1 "/pause" 23 seconds ago Up 23 seconds k8s_POD_etcd-docker-desktop_kube-system_f132e1c85abd4953a304d1c65d9d74f9_0

が、結果は変わらなかった

minikubeのインストール

Docker DesktopのKubernetesが動作しないのであればminikubeをインストールするしかなさそう

https://kubernetes.io/ja/docs/tasks/tools/install-minikube/
こちらを参考にインストール
kubectlも最新のものを利用するようにbrewでインストール

1
2
3
4
5
6
7
$ brew install virtualbox
$ brew install vagrant
# docker desktopでインストールされていたkubectlのシンボリックリンクをrename
# brew install kbuectlでリンクがはれずにエラーになるため
$ mv /usr/local/bin/kubectl /usr/local/bin/kubectl.docker
$ brew install kubectl
$ brew install minikube

Proxyを利用する環境での設定

無事インストールが終わる

1
2
3
$ minikube version
minikube version: v1.7.3
commit: 436667c819c324e35d7e839f8116b968a2d0a3ff

minikube startを実行してみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
💾 Downloading driver docker-machine-driver-hyperkit:
> docker-machine-driver-hyperkit.sha256: 65 B / 65 B [---] 100.00% ? p/s 0s
> docker-machine-driver-hyperkit: 10.88 MiB / 10.88 MiB 100.00% 5.52 MiB p
🔑 The 'hyperkit' driver requires elevated permissions. The following commands will be executed:

$ sudo chown root:wheel /Users/username/.minikube/bin/docker-machine-driver-hyperkit
$ sudo chmod u+s /Users/username/.minikube/bin/docker-machine-driver-hyperkit


Password:
💿 Downloading VM boot image ...
> minikube-v1.7.3.iso.sha256: 65 B / 65 B [--------------] 100.00% ? p/s 0s
> minikube-v1.7.3.iso: 167.39 MiB / 167.39 MiB [] 100.00% 14.63 MiB p/s 12s
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy:8080
⚠️ You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (192.168.64.2). Please see https://minikube.sigs.k8s.io/docs/reference/networking/proxy/ for more details
▪ HTTPS_PROXY=http://username:password@proxy:8080
▪ http_proxy=http://username:password@proxy:8080
▪ https_proxy=http://username:password@proxy:8080
⚠️ VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
💾 Downloading kubeadm v1.17.3
💾 Downloading kubelet v1.17.3
💾 Downloading kubectl v1.17.3
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

Proxyの設定を環境変数から自動的に認識してくれていて、必要な設定NO_PROXYが設定されてないとも教えてくれている
NO_PROXYが設定されてないからか、Server側の返答が来ない

1
2
3
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: context deadline exceeded (Client.Timeout exceeded while awaiting headers)

NO_PROXYを設定する

1
$ export NO_PROXY=192.168.64.2

NO_PROXYの指定はsubnet形式で行う方が良い(IP変わるので)

1
$ export NO_PROXY=192.168.64.0/24

念のためdelete

1
2
3
$ minikube delete
🔥 Deleting "minikube" in hyperkit ...
💀 Removed all traces of the "minikube" cluster.

起動

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy:8080
▪ HTTPS_PROXY=http://username:password@proxy:8080
▪ NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4
▪ http_proxy=http://username:password@proxy:8080
▪ https_proxy=http://username:password@proxy:8080
⚠️ VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
▪ env NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4
▪ env HTTP_PROXY=http://username:password@proxy:8080
▪ env HTTPS_PROXY=http://username:password@proxy:8080
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

今度は大丈夫そう

1
2
3
4
5
6
7
8
9
10
11
12
13
$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ kubectl cluster-info
Kubernetes master is running at https://192.168.64.4:8443
KubeDNS is running at https://192.168.64.4:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-11T18:07:13Z", GoVersion:"go1.13.6", Compiler:"gc", Platform:"linux/amd64"}

やっとServerが応答してくれたが、大丈夫じゃなかった
minikube start の時のメッセージ

1
⚠️  VM is unable to access k8s.gcr.io, you may need to configure a proxy or set --image-repository

proxyの設定は環境変数から自動的に取得してくれているのに、なぜかimageの取得が行えない
deploymentを作成してpodのステータスをみるとErrImagePullとなってしまう

1
2
3
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-797f975945-kl26w 0/1 ErrImagePull 0 54s

proxyの設定を見直してみると、proxyのホストをproxyとしてしまっていて、その名前が引けない
なのでIP指定にする
ローカルのPCにて設定

1
2
3
4
5
6
7
$ export HTTP_PROXY_USER=username
$ export HTTP_PROXY_PASSWORD=password
$ export HTTPS_PROXY=http://${HTTP_PROXY_USER}:${HTTP_PROXY_PASSWORD}@proxy_ip:8080
$ export HTTP_PROXY=http://${HTTP_PROXY_USER}:${HTTP_PROXY_PASSWORD}@proxy_ip:8080
$ export NO_PROXY=192.168.64.0/24
$ export http_proxy=$HTTP_PROXY
$ export https_proxy=$HTTPS_PROXY

再度minikube start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
🔥 Creating hyperkit VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...
🌐 Found network options:
▪ HTTP_PROXY=http://username:password@proxy_ip:8080
▪ HTTPS_PROXY=http://username:password@proxy_ip:8080
▪ NO_PROXY=192.168.64.0/24
▪ http_proxy=http://username:password@proxy_ip:8080
▪ https_proxy=http://username:password@proxy_ip:8080
🐳 Preparing Kubernetes v1.17.3 on Docker 19.03.6 ...
▪ env HTTP_PROXY=http://username:password@proxy_ip:8080
▪ env HTTPS_PROXY=http://username:password@proxy_ip:8080
▪ env NO_PROXY=192.168.64.0/24
▪ env HTTP_PROXY=http://username:password@proxy_ip:8080
▪ env HTTPS_PROXY=http://username:password@proxy_ip:8080
🚀 Launching Kubernetes ...
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"

大丈夫そう!

1
2
3
4
5
$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-minikube created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-797f975945-jnfkt 1/1 Running 0 24s

statusがRunningになっている
これでやっと環境が整ったので、アプリケーションの設定を行うことができるようになった

おまけ

minikube stopしてからのminikube startが動かない

1
2
3
4
5
6
7
8
$ minikube stop
✋ Stopping "minikube" in hyperkit ...
🛑 "minikube" stopped.
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Using the hyperkit driver based on existing profile
⌛ Reconfiguring existing host ...
🔄 Starting existing hyperkit VM for "minikube" ...

ここから動かないので一旦ctrl-Cで止める
もう一度やってみる

1
$ minikube start

全く反応しなくなる…
ステータスを確認

1
2
3
4
5
$ minikube status
host: Stopped
kubelet: Stopped
apiserver: Stopped
kubeconfig: Stopped

もう一回だけやってみるとさっきのところまでは進んだ

1
2
3
4
5
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Using the hyperkit driver based on existing profile
⌛ Reconfiguring existing host ...
🔄 Starting existing hyperkit VM for "minikube" ...

が、結局ここから動かないので一旦削除する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ minikube delete
🔥 Deleting "minikube" in hyperkit ...
💀 Removed all traces of the "minikube" cluster.
$ export NO_PROXY=192.168.64.2,192.168.64.3,192.168.64.4,192.168.64.5
$ minikube start
😄 minikube v1.7.3 on Darwin 10.13.6
✨ Automatically selected the hyperkit driver. Other choices: virtualbox, docker (experimental)
(省略)
🌟 Enabling addons: default-storageclass, storage-provisioner
⌛ Waiting for cluster to come online ...
🏄 Done! kubectl is now configured to use "minikube"
$ kubectl cluster-info
Kubernetes master is running at https://192.168.64.5:8443
KubeDNS is running at https://192.168.64.5:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:07:54Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-11T18:07:13Z", GoVersion:"go1.13.6", Compiler:"gc", Platform:"linux/amd64"}

次回はサンプルアプリを実行しながらKubernetesオブジェクトを理解していく

暗号技術入門(新版)

本書を読むきっかけ

普段の業務で、「APIにアクセスしているクライアントがTLS/1.2をサポートしているかどうか、また利用可能なCipherSuiteを教えてください」と連絡がきた。
あれ?どう調べていいか全くわからない…となってしまったので、SSL/TLSをしっかり理解するためにまずは家に積読されていた暗号技術入門を読むことに。
これをきっかけに暗号周りの技術的な基礎をしっかりと学びなおそうと思います。

全体の構成

暗号技術入門は全体で3部構成になっていて、1部は共通鍵暗号・公開鍵暗号・ブロック暗号などの暗号技術、暗号アルゴリズムについて詳しく説明されています。
2部では認証について記載されています。認証とは、ダウンロードしたファイルが正しいものかどうか?このメッセージを書いたのは誰か?などの本物かどうかを確認できる仕組みです。一方向ハッシュ関数・メッセージ認証コード・デジタル署名・証明書について詳しく説明されています。
3部では鍵とは一体何なのか?など、普段疑問に思わないところを深掘りしています。とてもおもしろい部分ではあります。

ちなみに暗号技術入門は第3版が出ています。こちらはブロックチェーンなど比較的新しい技術にも言及しています。あとで読む予定。

1部 暗号

1章は暗号技術をさらっとまとめていて全体を把握するようにしています。

2章は古くから伝わる暗号の歴史を紐解いています。歴史に興味のある人は読むとおもしろいかもしれませんね。

3章から本格的な暗号技術を見ていきます。と言っても対称暗号(共通鍵暗号)はあまり出番がなさそうですね…CipherSuiteとしてDES, 3DES, AESなどは出てくるので名前を覚えておくというのと、今後どの対称暗号を利用すればよいかをわかっておけばよいでしょう。(今後利用するならAESがよいと記載されています)
共通鍵暗号で問題になるのが、「鍵配送問題」というもので、共通鍵暗号なのでお互い共通の鍵を使うわけですが、その鍵をどうやって共有するか?共有する際に誰かに盗み取られないか?という問題です。これを解決するために「鍵交換プロトコルを利用する」方法と「公開鍵暗号方式を利用する」方法など複数あります。こういった問題が含まれているということも知っておくとセキュリティリスクを考える上で参考になります。

4章ではブロック暗号というあまり馴染みのないものです。といってもDES, AESもブロック暗号で、固定長ビットの平文しか暗号化できないのです…任意の長さの平文を暗号化するにはブロック暗号を繰り返し使う必要があったのです。そのブロック暗号を繰り返す方法のことをブロック暗号のモードといいます。モードの種類でCBCは聞いたことあるかもしれませんね。

5章ではやっとなじみのある公開鍵暗号方式が出てきます。まずはじめに先ほどの対称暗号を利用するときに問題になる「鍵配送問題」について触れ、その解決方法を4つ紹介しています。
次に公開鍵暗号方式の仕組み、通信の流れ、そして公開鍵暗号方式だけでは解決できない問題を提示しています。
公開鍵暗号といえばSSHの鍵を作成するときに利用される暗号化方式ですね。id.rsaが秘密鍵でid.rsa.pubが公開鍵です。公開鍵をログインしたいサーバーに配置してパスフレーズを入力してログインするのが公開鍵認証です。パスワード認証よりはセキュアですね。
鍵作成時にパスフレーズを入力しなければ、毎回パスフレーズなしでSSHログインできるので、よくログインするサーバには必ず公開鍵を置いておきます。本当に便利ですよね。ただ、そんな便利な公開鍵暗号方式にも欠点があり、暗号に利用する公開鍵が本当にその人が作った公開鍵なのかどうかがわからないという問題があります(公開鍵の認証)。情報を盗み取りたい人が作成した公開鍵で暗号化してしまうと、盗み取りたい人が復号化できてしまうという問題があります(man-in-the-middle攻撃)。それを解決するのが次の6章で紹介されるハイブリッド暗号システムです。

6章では対称暗号と公開鍵暗号のそれぞれの問題点を解決するためのハイブリッド暗号システムの仕組みを紹介しています。
まずそれぞれの暗号方式の問題点をまとめています。

  • 対称暗号方式
    • 鍵配送問題
  • 公開鍵暗号方式
    • 対称暗号に比べて処理がずっと遅い
    • man-in-the-middle攻撃に弱い
      ハイブリッド方式は対称暗号方式の鍵配送問題と公開鍵暗号の処理の遅さを解決する方法です。(man-in-the-middle攻撃に関しては認証の問題で第2部で解説があります)

ハイブリッド暗号方式は

  • メッセージは対称暗号で暗号化する
  • 対称暗号の暗号化で使うセッション鍵は擬似乱数生成器で生成します
  • セッション鍵は公開鍵暗号で暗号化します
  • 公開鍵暗号の暗号化で使う鍵は、ハイブリッド暗号システムの外部から与えます

という仕組みで成り立っています。
公開鍵認証方式の遅さを暗号化するデータを小さくすることで補っており、大量データの暗号化は速い対称暗号方式で暗号化するというメリットを最大限に利用する暗号化方式です。

2部 認証

認証とは何かによって対象(データ)が正しいということを確認することです。
2部は7,8,9,10章から成り立っています。

7章ではデータが正しいことを証明するのに利用されている一方向ハッシュ関数を学びます。Webサイトからデータをダウンロードする際に付いている64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。64文字の文字列はこの関数で生成されています。一方向ハッシュ関数では改竄は防げるものの、なりすましを防ぐことはできません。

8章ではメッセージ認証コードについてです。
メッセージ認証コードを利用すると、先ほどの一方向ハッシュ関数では防げなかったなりすましを防ぐことができます。
メッセージ認証コードは送信者と受信者が共有する鍵とメッセージを元にして固定ビット長の出力を計算する関数です。なので、メッセージ認証コードは鍵に依存した一方向ハッシュ関数と考えると理解しやすいです。
データを送った人、データを受け取った人それぞれで共有鍵を利用しMAC値を算出、同じだったら認証成功というわけです。比較的シンプルですが共有鍵を利用しているので、鍵配送問題が起こります。鍵配送には3章に記載の鍵交換プロトコルなどを利用します。
メッセージ認証コードはIPSecやSSL/TLSなどで用いられています。
HMACという名前を聞いたことがあるかもしれません。HMACは一方向ハッシュ関数を用いてメッセージ認証コードをさ構成する手法です(RFC2104で定義されています)。HMACの具体的な手順は割愛しますが、いかにも暗号技術と言う手順で作成しているので、興味のあるかたはぜひ! https://www.ipa.go.jp/security/rfc/RFC2104JA.html

メッセージ認証コードで解決できない問題

  • 第三者に対する証明ができない
    第三者がMAC値を検証するには共通鍵を知る必要がある。仮に教えたとしても、そのMAC値を作ることができる人を特定することはできない(共通鍵を知っている人なら作成可能)
    これを解決するには9章でお話しするデジタル署名を利用します。
  • 否認防止ができない
    ボブがMAC値付きのメッセージを受け取ったとします。ボブはアリスと共有している鍵を使って計算したものであれば、これがアリスからだとわかります。
    しかしこれを第三者に対して証明することができません。つまり、アリスは「私はそんなメッセージを送っていない」と第三者に対して主張できてしまうことになります。このような主張のことを否認といいます。MAC値からではボブとアリス、どちらの主張が正しいのか判断できません。このような問題にもデジタル署名を使えば、否認防止が可能になります。

9章はデジタル署名です。
メッセージ認証コードで解決できなかった問題が二つありました(第三者へ証明できない、否認防止ができない)。
それらの問題は、アリスとボブの間で鍵を共有する必要があったためです。片方が送ったデータをもう片方でも正しいMAC値が計算できてしまうため、どちらが送ったを第三者に証明することができません。
同じ鍵を使っていることが問題であるなら、別の鍵を使うことにするのはどうでしょうか?アリスはメッセージ送信時に自分だけが知っているプライベートな鍵を使って「署名」を作成します。受信者のボブは別の鍵(公開鍵?)を使ってその「署名」を検証する。ボブの鍵では「署名」を作成できないが、鍵を使って検証することはできる。
こうすることで、改竄の検出、なりすましの検出、否認防止が可能になります。これがデジタル署名です。

10章は証明書です。公開鍵認証が相手を特定する上で、また鍵を共有する上で有効であることはわかりました。しかし、自分が持っている公開鍵が正しいものであるかどうかがわからないと、man-in-the-middle攻撃にやられてしまいます。公開鍵が正しいものかどうかを証明するものがこの章で説明する証明書になります。
証明書といえばやはりSSL証明書ですね。CSR作成して認証局に送って証明書を発行してもらうみたいな作業を訳もわからずやっていたのですが、なぜその手順を行うのかしっかり理解したいです。

証明書とは何か

証明書(公開鍵証明書)は公開鍵に対して、認証局(CA: certification authority)によるデジタル署名が行われているものです。

認証局とは何か

認証局とは「確かにこの公開鍵はこの人のものである」と認め、デジタル署名を作成できる人や組織のことです。つまり認証局はその公開鍵(証明書)の持ち主を保証する機関であると言えます。

証明書を使うシナリオ

証明書を利用するシナリオ(SSL証明書など)で証明書の役割を理解する

登場人物

  • ボブ(メッセージ受信者)
  • アリス(メッセージ送信者)
  • トレント(認証局)

シナリオ

  1. ボブがキーペアを作成する
  2. ボブが認証局トレントに自分の公開鍵を登録する
  3. 認証局トレントがボブの公開鍵に自局(トレント)の秘密鍵でデジタル署名をして証明書を作成する
  4. アリスは認証局トレントのデジタル署名がついたボブの公開鍵(証明書)を入手する
  5. アリスは認証局トレントの公開鍵を使ってデジタル署名を検証、ボブの公開鍵が正しいことを確認する
  6. アリスはボブの公開鍵でメッセージを暗号化しボブへ送信
  7. ボブは暗号化されたメッセージを自分の秘密鍵で複合化しアリスのメッセージを読む

基本的には公開鍵認証であるが、信頼できる第三者(認証局)のデジタル署名(秘密鍵での暗号化)によって公開鍵の信頼性を保証している。
このシナリオの2番がSSL証明書作成時のCSRに相当する。

証明書関連の規格

SSL証明書を作成したことがある人なら聞いたことがあるX.509や公開鍵基盤(PKI)などの解説も丁寧にされており、しっかり理解しておきたい。

証明書に対する攻撃

問題のなさそうな証明書の仕組みにもまだ攻撃できる余地があり、どういった攻撃が可能かの紹介がされています。

  • 公開鍵の登録前を攻撃

認証局にデジタル署名されてしまうと攻撃しづらくなるので、デジタル署名される前の公開鍵を攻撃します。公開鍵をすり替えるなどの方法があります。

  • デジタル署名を依頼する時の本人情報を攻撃対象者と似せる

コンピュータには別人と認識できるような情報でも人間には別人に見えないような情報でデジタル署名を依頼し、証明書の情報を誤認させます。正しくはBobだがBOB、BObなど、パッと見あっているような情報で登録するということです。

  • 認証局の秘密鍵を盗み出す攻撃

認証局の秘密鍵を盗むのは困難でしょう。盗まれないように認証局もセキュリティを万全にしているはずです。万が一、認証局の秘密鍵が盗まれた場合は、CRLを使って利用者に通知する必要があります。

証明書Q&A

Q&Aで紹介されている内容は証明書の必要性を説明してくれていて、モヤモヤを解決してくれる。いくつか紹介しよう。

Q. 証明書がなぜ必要なのか?
A. 信頼できない経路で公開鍵を入手した場合、man-in-the-middle攻撃が可能になります。その公開鍵が本当にその人が作成した公開鍵と保証できないからです。
認証局から証明書を入手すると、man-in-the-middle攻撃の可能性を減らすことができます。なぜなら証明書に含まれている公開鍵には認証局のデジタル署名が付いているため、すりかえることが事実上できないからです。
直接手渡しするなど信頼できる経路で公開鍵を受け取る場合は認証局は不要です。

  • 信頼できる公開会議を入手できるなら認証局は不要
  • 信頼できる認証局の公開鍵を持っていて、認証局の本人確認を信頼するなら、その認証局の発行した証明書によって入手した公開鍵は信用できる。

Q. 認証局はどうやって信頼するのか?
A. 「信頼」がどのように生まれるかという本質的な問題であって、答えとしては信頼できそうだからというもの。信頼できそうな認証局であれば信頼できるということだ。

証明書まとめ

証明書のパートだけ長くなってしまった。もともとSSL/TLSをしっかりと理解したいという欲求から本書を読み始めてしまったせいもある。
証明書は信頼できる第三者のデジタル署名がついている公開鍵であり、標準規格はX.509である。
認証局の役割、公開鍵基盤(PKI)などを学びました。

3部 鍵 乱数 応用技術

3部ではまず鍵について再考する。次に乱数について深掘りする。
その後は暗号技術の組み合わせのPGP、もともとの目的であったSSL/TLSについて記されている。
最後にまとめの章がある。

11章 鍵

鍵とは何か?

あらゆる暗号技術には必ず鍵と呼ばれる大きな数が必要になる。
重要なのは鍵そのものの大きさよりも鍵空間の大きさ、すなわちどれくらいの数の鍵が生成可能かということ。
その大きさはビット長で決まる。

  • 鍵の価値
    対称暗号(共有鍵暗号)を利用して、平文を暗号化したとする。鍵を盗まれてしまった場合、その鍵を利用して暗号化された平文の内容がわかってしまう。
    鍵が他人に渡ってしまう=平文が他人に渡ってしまうということ、すなわち鍵は平文と同じ価値があるということである。

  • 暗号アルゴリズムと鍵
    暗号アルゴリズムを秘密にすることで情報の機密性を守ろうとするのは危険。暗号アルゴリズムではなく鍵を秘密にすることで情報の機密性を守るのがよい。

さまざまな鍵

  • 鍵の用途
    対称暗号(共通鍵暗号)の鍵や、公開鍵暗号の鍵はデータの気密性を保つための鍵である。メッセージ認証コードやデジタル署名で使われる鍵は、認証を行うための鍵である。

鍵を管理する

  • 鍵を作る
    • 乱数から鍵を作る
    • パスワード(パスフレーズ)から鍵を作る
  • 鍵を配送する
    • 鍵配送問題
      • 解決方法
        • 鍵の事前共有(pre-shared key)
        • 鍵配布センターを利用する
        • 公開鍵暗号
        • Diffie-Hellman鍵交換
  • 鍵を保存する
    • 安全な場所に保存する
    • 暗号化して保存する
      • 鍵を暗号化するための鍵が必要(KEK)

Diffie-Hellman鍵交換

  • Diffie-Hellman鍵交換とは
    鍵配送問題を解決する方法の一つ。
    他人に知られても良い情報を交換するだけで共通の秘密の数を作り出すという方法。

  • Diffie-Hellman鍵交換の手順
    アリスとボブが対称暗号の鍵を共有する場合

  1. アリスはボブに対して2つの素数P, Gを送信する
    Pは非常に大きな素数でなければならない。Gは生成元と呼ばれる数でPに依存する。
  2. アリスは乱数Aを用意する
    Aは1からP-2の間にある整数。Aはアリスだけの秘密の数。
  3. ボブは乱数Bを用意する
    Bも1からP-2の間にある整数。Bはボブだけの秘密の数。
  4. アリスはボブに対してG^A mod Pという数を送信する
    これは他人に知られても構いません
  5. ボブはアリスに対してG^B mod Pという数を送信する
    これは他人に知られても構いません
  6. アリスはボブから送られてきた数をA乗して、mod Pを取る
    これが鍵になる。
    アリスの計算
    (G^B mod P)^A mod P
    = G^BxA mod P
    = G^AxB mod P
  7. ボブはアリスから送られてきた数をB乗して、mod Pを取る
    アリスから送られてきた数
    G^A mod P
    をB乗してmod P
    (G^A mod P)^B mod P
    = G^AxB mod P

6で得た数と7で得た数は同じ、なので共通の鍵を得たことになる。

  • イブ(盗聴者)は鍵を計算できないのか?
    イブが知り得る数はP, G, G^A mod P, G^B mod Pの4つ。
    この4つの数からG^AxB mod Pを計算することは極めて困難だと考えられている。
    もしAかBどちらかでもわかればG^AxB mod Pを計算することは可能。
    しかしG^A mod Pから数Aを簡単に計算するアルゴリズムはまだ発見されていない。
    有限体の上の離散対数問題と呼ばれている。