hitsumabushi845の日記

心理的安全性の保たれた空間に書く適当なメモ

半年経ったので2021年の目標をふりかえる

2021年も半分がすぎたので、https://hitsumabushi845.hatenablog.com/entry/2021/01/02/092252 で掲げた目標について、現状を確認して下半期の動き方を考える。

資格をとる

今年受検したいと思っているものは以下の通り。 - CKA or CKAD
- TOEIC

CKAD は先日取得した。学習ログはこのブログに、受検ログは Qiita に投稿した。
考えてみると IT 系の資格を取ったのはこれがはじめてであった。試験自体久しぶりなのでかなり緊張した。

qiita.com

下半期は CKA の取得をはやめに済ませたい。
TOEIC は今年受けるかどうか微妙だなあ。

こまめにブログを書く

このブログでは特定の技術に関する話題以外の、技術以外の話やポエムなどを書いていきたいと思っている。
特定の技術要素については、せっかく Organization に属しているので Qiita に書くつもりでいる。 こまめにと言っても、せいぜい月2程度のペースでゆるくやっていきたい。

上半期、Qiita には 9 件の記事を投稿している。 このブログには主に CKAD の学習ログを投稿しており、合算すると月2のペースはクリアできている。

今後もこれくらいのペースで投稿できるとよい。

Terraform を勉強する

2021年から本業・副業ともに Terraform を扱うようなので、ゆるく勉強する。
仕事で使うのでまあ勉強できるだろうと高をくくっている。 特に到達目標はないが、仕事が回る程度に扱えればよいと思う。

これは具体的になにか勉強をしているわけではないが、業務で扱う中でなんとなく雰囲気は掴めた気がする。
ちなみに Terraform では GCP と OCI を主に扱っている。

golang を勉強する

そろそろ新しい言語を勉強したい。
golang は、複数のプラットフォームに向けてコンパイルできるということで、かねてより興味は持っていたが、
Kubernetes に触れるようになったことでより勉強するモチベーションが上がっている。 とりあえず、Gopher 道場 を進めていこう。

これが全然できていない。。 業務で必要にならないとやっぱりモチベーションが上がらないのがよくないところ。 必要になったらやろう()

というわけで

まあおおむね目標通りに進んでいるように思う。 この調子で下半期もやっていければいいんじゃないでしょうか。

『Kubernetes Certified Application Developer (CKAD) with Tests』記録 - セクション8

引き続き、『Kubernetes Certified Application Developer (CKAD) with Tests』を進めていく。
今回は Section 8: State Persistence。ここまでで試験範囲は終わり。以降は Mock Exam(模試) となる。

Section 8: State Persistence

Volumes

コンテナが生成するデータ(ファイル)を永続化させるため、Pod に Volume をアタッチする。 以下に示すマニフェストでは、ノードの記憶領域をコンテナに /opt としてマウントしている。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
  - image: alpine
    name: alpine
    command: ["/bin/sh", "-c"]
    args: ["shuf -i 0-100 -n 1 >> /opt/number.out"]
    volumeMounts:
    - mountPath: /opt
      name: data-volume
  volumes:
  - name: data-volume
    hostPath:
      path: /data
      type: Directory

hostPath は特定のノード(Pod の配置されるノード)の記憶領域を利用するが、マルチノードの場合やノードのフェイルオーバーなど、ノードが替わった場合に一貫性が損なわれる。 そのため、通常は後述する Persistent Volume によりクラウドストレージ等を利用して永続化を図る。

volume の種別は他に、emptyDir, downwardAPI, projectedなどがある。 emptyDir は一時的な領域で、Pod が terminate されると削除される。downwardAPI は Pod の情報などをファイルとして保持するためのもの、projected は複数の volume をまとめるもの。

Persistent Volumes

Persistent Volumes(PV) は、ストレージ空間を提供するプールのような役割をしている。 大量の Pod をデプロイする場合に、各マニフェストで逐一 Volume を管理するのではなく、PV によって利用されるストレージを作成・管理し、Pod からは Persistent Volume Claim(PVC) を用いて利用する。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-sample
spec:
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  capacity:
    storage: 1Gi
  hostPath:
    path: /tmp/data

Persistent Volume Claims

先述した PV を Pod から利用するためのリソース。 accessModesresources に指定した内容に合致する PV が紐付く。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-sample
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi

素の k8s では、PV を作って PVC を作って... という流れで利用するが、GKE などではデフォルトでいい感じの StorageClass (kubernetes.io/gce-pd)が設定されており、PVC を作るだけで PV が Dynamic Provisioning される。

Storage Classes, Stateful Sets...

これらは CKAD の範囲ではないそうなので、今はスキップ。

『Kubernetes Certified Application Developer (CKAD) with Tests』記録 - セクション7

引き続き、『Kubernetes Certified Application Developer (CKAD) with Tests』を進めていく。
今回は Section 7: Services & Networking。

Section 7: Services & Networking

Services

k8s 内で動いている Web アプリケーションに対して、クラスタ外から単に Pod の IP アドレスにアクセスしてもアプリケーションへアクセスできない。
これは、Pod IP は異なるネットワークであり、クラスタ外からは見ることができないものだからだ。

クラスタ外から到達できる IP は基本的にノードの IP となる。そのため、ノードへのアクセスを所望の Pod に配分するリソースが必要となる。
この際作成するサービスは、例えば NodePort サービスが挙げられる。これはノードの特定のポートに来たリクエストと、指定した Pod や Deployment との間のやりとりを仲介するリソース。

ほかに、

  • ClusterIP
    クラスタ内でのみ疎通性のあるロードバランシング/ディスカバリを行うリソース。
  • LoadBalancer
    外部疎通性のある IP を払い出し、ノードに対するロードバランシングを提供するリソース。クラウドプロバイダが提供する LB を作成する。

などがある1

NodePort Service はクラスタ内に作成された ClusterIP Service に対してノードの特定ポートを利用した外部疎通性を確保しているもので、トラフィックの経路としては Node の特定ポート -> ClusterIP Service -> Target Pod といった流れとなる。
同様に、LoadBalancer Service は NodePort Service に対する外部疎通性を確保するものである。

そのため、NodePort を作成したら内部的には ClusterIP も併せて作成され、LoadBalancer を作成したら NodePort も作成される。
このような ClusterIP <- NodePort <- LoadBalancer といった関係は、Pod <- ReplicaSet <- Deployment や、Job <- CronJob といった親子関係に似ている。

Services - ClusterIP

Deployment によって冗長化された Pod に対して、他の Pod からリクエストを送る場合、内部的なロードバランシングが必要となる。
この場合に利用されるのが ClusterIP Service であり、先述のとおりこれはクラスタ内でのみ利用可能な Service。

Ingress Networking

提供するサービスごとにコンテナを分けるといったマイクロサービス的なデプロイをした場合、サービス全体を外部公開した際にパスベースのルーティングを行いたいケースがある。
NodePort や LoadBalancer はあくまで L4 のロードバランシングを行うため、パスベースルーティングといった L7 のロードバランシングを行うためには、リバースプロキシのようなものが必要になる。

Ingress リソースは L7 のロードバランシングを提供する。
Pod や Service といったリソースのように、マニフェストファイルをもとに L7 ロードバランサを提供することができ、K8s 内で一貫した外部疎通性の確保が可能となる。

Ingress リソースは、デフォルトのクラスタでは提供されていない。多くのマネージド k8s では、クラウドプロバイダが提供する外部の LB と連携した Ingress Controller がデプロイされている。
そうでないクラスタ(オンプレミスのクラスタOracle Cloud Infrastructure の k8s などが該当する)では、Nginx controller を利用することとなる。

前者の外部 LB を利用した方法では、外部 LB がそれぞれの NodePort へトラフィックを転送する。
後者の場合は、クラスタ内に Nginx Ingress controller がデプロイされるため、別途 LoadBalancer や NodePort で外部疎通性を確保することとなる。LoadBalancer サービスは Nginx controller へトラフィックを転送し、Nginx controller が各 Pod へトラフィックを転送する。

Network Policies

Pod 間の通信ルールを設定するリソース NetworkPolicy について。
Kubernetes では、NetworkPolicy を設定しない場合は全ての通信が許可される。

NetworkPolicy では、Pod への通信である ingress rule と、Pod からの通信である egress rule を設定できる。 NetworkPolicy を設定した場合、そこで許可されていないトラフィックはすべて拒否される。

マニフェストの例は以下の通り。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
      podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Developing network policies

上記マニフェストの各種ルールについて。

  • ipBlock
    指定した CIDR から/へ の通信を許可する。
  • namespaceSelector
    指定した namespace から/へ の通信を許可する。
  • podSelector
    指定した Pod から/へ の通信を許可する。

from/to にリストのアイテムとして指定されたルールは、それぞれが or 条件として処理される。アイテム内に複数のルールを指定した場合は、and 条件として処理される。


  1. ほか、ExternalIP や ExternalName など。

『Kubernetes Certified Application Developer (CKAD) with Tests』記録 - セクション6

引き続き、『Kubernetes Certified Application Developer (CKAD) with Tests』を進めていく。
今回は Section 6: POD Design。

Section 6: POD Design

Labels, Selectors and Annotations

リソースを分類する方法について。
ラベルは metadata.labels に設定でき、設定したラベルにしたがって kubectl get pods --selector key=value といったように絞り込むことができる。

ReplicaSet や Deployment では、ラベルをもとに指定したリソースの数を判断している。 また、Service では、ターゲットとなるリソースをラベルから指定できる。

上述の通り、ラベルはリソースを分類・振り分けするためのフィールドだが、アノテーションはそのほかの情報を付与するためのフィールド。 ... と説明されているが、場合によってはアノテーションも分類・振り分け用途に使う気がする...

Rolling Updates & Rollbacks in Deployments

Deployment のローリングアップデートとロールバックについて。
Pod では、使用しているコンテナイメージを更新するためには Pod の再作成が必要になる。 一方、Deployment では配下の Pod についてコンテナイメージの更新をローリングアップデートで行える。

Deployment では、アップデート戦略(StrategyType)のデフォルトが RollingUpdate であるので、 ローリングアップデートは kubectl set image でイメージを変更するか、マニフェストを更新して kubectl apply をするだけでよい。
StrategyTypeRecreate にすると、Deployment であっても再作成により更新が行われる。

変更のロールバックには kubectl rollout undo が使用される。リビジョンを指定しなかった場合は1つ前にもどる。
リビジョンは kubectl rollout history で確認できる。

ここのハンズオンは結構楽しい。Recreate と RollingUpdate の挙動について実際に手を動かして確認できた。

Jobs, CronJobs

Job について。
Pod などのリソースは常に動作していることが期待されるものだが、Job はバッチ処理など、特定の実行単位があり、終了する処理を行うリソース。

Pod でも終了する処理を実行することは可能だが、終了してしまうがゆえにヘルスチェックに失敗し、コンテナの再起動が走ってしまう。 また、Job では、同一の処理を並列で実行させたり、成功数を規定できたりする。

CronJob は、指定した時間に Job を作成するリソース。spec.schedule に cron と同じフォーマットで時間を指定できる。

apiVersion が、Job は batch/v1, CronJob は batch/v1beta1 なのに注意。

『Kubernetes Certified Application Developer (CKAD) with Tests』記録 - セクション4・セクション5

前回の記録から間が空いてしまったが引き続き、『Kubernetes Certified Application Developer (CKAD) with Tests』を進めていく。
今回は Section 4: Multi-Container PODs と Section 5: Observability。

これらのセクションは結構短い。

Section 4: Multi-Container PODs

マルチコンテナ Pod のパターンについて、アプリケーションコンテナとロギングを扱うコンテナの2つのコンテナを例に説明。このセクションは以下の説明と Practice test のみ。

  • Sidecar pattern
    アプリケーションコンテナのログをログサーバなどのサービスに送信するなど、補助的な機能をもつコンテナを配置する。
  • Adapter pattern
    アプリケーションコンテナのログをフォーマットするなど、外部とのインターフェースを提供するコンテナをもつパターン。アダプタコンテナがインターフェースを担うことで、アプリケーションコンテナ自身のログの柔軟性を高めることが出来る。
  • Ambassador pattern
    アプリケーションコンテナのログの送信先を扱うような、外部のサービスとの接続を仲介するコンテナを持つパターン。このコンテナがあることで、アプリケーションコンテナからは常にこのコンテナ(localhost)に接続すればよく、アンバサダーコンテナを差し替えることで接続先を柔軟に切り替えられる。

Practice Test は、Elasticsearch に Sidecar コンテナからログを送信し、Kibana からログを閲覧できるようにするハンズオンだった。といっても既存の Pod に指定のコンテナを追加するだけだが。

Section 5: Observability

Readiness Probes

Pod が作成されると、Pending -> ContainerCreating -> Running といったように、Status が遷移する。 コンテナが起動した後、"Running" であることを Kubernetes はどう知るのか?
Jenkins を Kubernetes で立ち上げると、Web 画面は利用可能でないが Pod は "Running" になる。 Service は "Running" な Pod にルーティングするので、アプリケーションとして利用可能でないのにルーティングされてしまう可能性がある。

そこで、アプリケーションが利用可能であること(リクエストを受け付けることができること)を Readiness Probes を用いて検証する。 これは HTTP APITCP, コマンド実行で検証する。 この検証に失敗した場合、Service はその Pod へトラフィックをルーティングしない。

これは spec.containers[*].readinessProbe に設定する。

    readinessProbe:
      httpGet:
        path: /api/ready
        port: 8080
    readinessProbe:
      tcpSocket:
        port: 3306 
    readinessProbe:
      exec:
        command:
        - cat
        - /app/is_ready

Liveness Probes

Docker では、コンテナの作成に失敗したらそのコンテナは失敗したままだが、Kubernetes では Pod の作成に失敗したら、再作成を行う。 Pod の作成に成功したこと(Pod 内のコンテナが正常に動作していること)を検証するための機構が Liveness Probe。 この検証に失敗した場合、コンテナを再起動する。

こちらも同様に、HTTP API call や TCP, コマンド実行で検証を行う。

書き方は、おおむね Readiness Probe の readinessProbelivenessProbe に変更したもの。

Container Logging

kubectl logs コマンドについて。Pod 名を指定して Pod のログを見たり、加えてコンテナ名を指定してコンテナのログを絞って見たり。ここは普段よく使っているので流す。

Monitor and Debug Applications

kubernetes のノード監視について。通常の運用では Prometheus や Datadog などを使ってメトリクスを記録していくが、CKAD では公式に開発されている Metrics Server を用いるようだ。過去は heapster というコンポーネントだったが、今は metrics-server らしい。

こいつはメモリ上に記録するため、メトリクスを過去に遡って見ることはできないが,kubectl top コマンドでノードや Pod のメトリクスを確認できるようになる。

7ヶ月かけて NURO を開通させた話

もうタイトルで言いたいこと全て言っているのだが、7ヶ月かけて NURO を開通させた。 これはなにも NURO の工事に7ヶ月待たされたという話ではなく、「初めての一人暮らし」であったり「賃貸物件の共用部への工事」といった要素が絡み合って時間がかかってしまった。

特に後者の「賃貸物件の共用部への工事」を解決するための戦いに多くの時間を費やし、先日ついに開通したためその記録を残したい。

引っ越しと1度目の宅内工事

昨年9月に実家を出る形で引っ越しをした。実家でも NURO を通していたこと、またリモートワーク環境を整えるための引っ越しであることから、引き続き NURO を利用しようと考えていたため、物件探しの段階で「NURO の工事が可能なこと」を条件に物件を探していた。

その後工事可能なマンションを契約し、引っ越し予定日に宅内工事を予約した。

そして宅内工事当日。 集合住宅の場合、宅内工事は宅内から MDF 盤まで光ファイバを通すことを目的とする。 つまり、部屋 (-> IDF) -> MDF といった経路で光ファイバを通すことになる。

MDF(Main Distribution Frame): 集合住宅やオフィスビルの共用部に設置される電話回線や光ファイバなどの集線装置。
IDF(Intermediate Distribution Frame): MDF から各戸分配するにあたって中間に設置される中継機器。複数フロアの物件の場合は通常各階に設置される。

しかし、この工事では 部屋 -> IDF の経路でファイバを通す途中でファイバが詰まってしまい、IDF まで通せないという事態に陥った。既設の電話回線等により配線を通すパイプが詰まっていたのである。

工事作業者と一緒になって、ファイバの通る音を頼りに詰まってしまっている地点を特定したが、そこは共用部(マンション廊下の天井裏)であり、またその地点に点検口などといったものが無かった。

そのため、この宅内工事では「別途点検口を設けるなどして、通線可能な状態にならない限り開通不可能」という結論となった。

ここでの学び

  • 入居前の「工事可能」はできるだけ厳密に確認しておく
  • 光アウトレットが既設の物件であればなおよい(こういった物件はほぼ築浅なので家賃は高い)
  • IDF とか MDF とか、このへんではじめて知った

点検口を開けてもらうための5ヶ月

さて通常、集合住宅かつ賃貸物件の場合は共用部へ点検口を設けるなどといった工事は許容されないことが多い。特に今回問題になっているのは 部屋 -> IDF の経路であるため、ここに点検口を設けるとなると他のフロアにも等しく設ける必要があるかもしれない。オーナーがこのコストを支払うのを避けたい気持ちは十分に理解できる。 しかしそもそも私は「工事が可能」という条件で物件を契約しているため、これを武器に戦うこととした(たとえ、この条件が不動産屋が深く考えずに発言した内容であっても)。

物件は私とオーナーとの間に管理会社が入っているので、まずは管理会社と交渉することになる。 ここからが長い戦いの始まりであった。

最初の1ヶ月

最初の1ヶ月は、まず管理会社に「なぜ NURO を通したいか」を理解していただくための期間であった。 集合住宅の場合、一口に光回線といっても各戸分配する方式によって品質が大きく変わる。(参考: https://internet-flets-campaign.net/column/separatefiber/

このマンションには NTT の VDSL 設備はすでに備わっているため、対外的には「光回線が利用できます」と謳っていたし、管理会社の方もまた「光回線が利用できる」という認識であった。 そのおかげで、まず「なぜ NURO を通したいか」の説明が必要となった。

もちろん、光配線方式がとれればどの事業者でもよいので、個人的には NURO でもフレッツでも何でもよかった。 しかしフレッツはサービスとして VDSL と光配線の両方を提供している。 以下に示すやりとりを経て、「フレッツを利用したい」というスタンスでいると余計な混乱を招きそうと判断し、「NURO を通したい人」で通すことにした。

NTT の VDSL 設備が備わっている場合、VDSL 方式のフレッツ光は当然今のままでも利用可能である。 そのためか、管理会社から「フレッツなら光回線を通せます」という旨の回答を受けた。

この回答を逆手に取り、フレッツ光なら通せるんですか?光配線方式でも?」 と質問したところ、おそらくあまり考えておらずに 「はい!通せます!」 と返ってきた。
もちろん通せるわけはないので、 「本当に通せるんですか?光配線方式って何か分かってますか?」 と改めて確認したところ、 「はい!わかります!」 と返ってきた。
分かっているとのことなので、改めて VDSL 方式と光配線方式の違いを説明できますか?」 と確認した。

すると ADSL ですか?」 と返ってきたため、改めてこれらの違いを説明し、理解いただいた。 ほかにも、「NURO が使える物件は付加価値が高まりますよ」的なことも(無責任に)言った気がする。

ここで辛抱強く説明を重ねて理解いただいたことで、以降管理会社の方がこちらの味方についてくれることとなる。このステップがなかったら以降の点検口開口の交渉も難しかったのではないかと思う。

これが最初の1ヶ月。

ここでの学び

  • 辛抱強く説明すると分かってくれることがある
  • 分かってくれると味方になってくれることがある
  • VDSL 方式と光配線方式の違いについて結構調べた

その後の3ヶ月

「なぜ NURO を通したいか」を理解いただいてからは、管理会社と物件オーナーとの交渉となる。 交渉の目的は点検口の工事可否確認になるのだが、先述の通り物件オーナーからすると共用部への工事は敬遠される。

さて、この期間は管理会社とオーナーの間での交渉が行われていたため、基本的に私がすることはなかった。 この間に私がしていたことは主に以下の2つである。

進捗確認

1つ目が進捗の確認。これは管理会社側が交渉の進捗をこちらに報告してくれないためであった。そもそもこちらから問い合わせないと報告しないというスタンスならそれでよかったが、彼らはいつも「いついつまでに改めてご連絡します」と言っていたのにも関わらずそれを守らなかったのであった。思い返してみると、これが守られたことは1度もなかったように思う。

そのため、平均的には2週間に1度、多いときは週に1度のペースで確認を取っていた。

直接引き込みの可否確認

そして2つ目が「点検口を開けずに工事を行う方法の確認」である。 そもそも私は「ただ単に点検口を開けたいだけの人」ではなく「NURO を通したい人」であるので、点検口を開けずに工事が可能ならそれでも良かったのだ。

点検口を開ける必要があるのは 部屋 -> IDF -> MDF といった経路での通線を行う場合であって、直接部屋に引き込むことができればその限りではない。実際 NURO は集合住宅であっても場合によっては部屋に直接引き込むことが可能である。(参考: https://www.nuro.jp/article/mansionjyouken/)

つまり、for マンションプランでなく通常プランであれば電柱から直接光回線を自室に引き込むことができる。通常プランは、以前は7階建て以下の集合住宅という条件があったものの、この条件は2019年に撤廃されたそうだ。

自室に直接引き込むことができれば、IDF や MDF のことを考えずに済むため、こちらの可能性についても検討した。

さて、自室に直接引き込むにあたり障壁となるのが「壁への穴開け」である。外壁から屋内にファイバを通すための穴開け、並びに穴へのカバー取り付けのためビス留めが必要となるのである。これらは外壁への穴開けとなり、賃貸物件の場合はほぼ容認されない工事となる。

しかし、これについても回避することが可能である。詳細はこの記事を確認してほしい。

要約すると、エアコン等の配管を利用してファイバを通し、ビス留めは両面テープで代替するなどの方法による回避である。

外壁への穴開けを回避できることが分かったため、管理会社に「外壁への穴開けがなければ工事してもよいか」、NURO に「私の住んでいる物件は直接引き込みが可能か」の確認をそれぞれ行った。

前者は穴開けがなければ良いとのことだったが、後者が不可能であった。つまり、私の住んでいる物件は直接引き込みができないのであった。

従って、NURO を開通させるにはやはり点検口を設けてもらうしかないということとなった。

そして

さて、これらのことを進めている間に管理会社とオーナー間の交渉は進んでいた。 管理会社の尽力のおかげか、オーナーの理解も得られ、点検口開口の工事が可能となったのである。

これが2021年1月中旬の出来事である。開始からすでに4ヶ月が経過していた。

ここでの学び

  • NURO は集合住宅であっても場合によっては直接引き込むことが可能
  • NURO は直接引き込みの際、場合によっては外壁に穴開けをしない施工が可能

最後の1ヶ月

ここは実際に点検口を開ける工事を待つだけのほぼ消化試合であった。 そして2月中旬、ついに点検口が誕生した。

つなぎの VDSL

引っ越し当初は、まず引っ越し予定日に宅内工事完了、その後1〜2ヶ月で屋外工事完了といったスケジュール感でいたため、モバイル Wi-Fi(WiMAX) をレンタルして仕事をしていた。

しかし、戦いが長丁場になりそうだったこと、モバイル Wi-Fi では仕事にならないことから、つなぎになる VDSL を契約することとした。

つなぎに利用する回線は、契約期間の縛りがないことが優先される。 NURO が開通できた場合即座に解約することとなるため、違約金等が発生するのは避けたい。また、契約期間の縛りがなければ、NURO の開通が不可能であった場合も改めて適切な事業者を選択することができる。

契約期間の縛りがないプロバイダは検索するといくつか出てくるが、enひかりを選択した。IPv6 オプションを追加することで IPoE での接続が行えるためだが、他でもできたかもしれない。

この VDSL は 12 月に開通した。都合 4 ヶ月で解約することとなったが、モバイル Wi-Fi から解放してくれて感謝している。

ここでの学び

  • NURO の工事待ちが長期化することが見込まれる場合、契約期間の縛りのないプロバイダを契約するとよい
  • モバイル Wi-Fi をレンタルし続けるくらいなら、さっさとつなぎの回線を契約した方がよい(工事費がかかるが、モバイル Wi-Fi による諸々のストレスをなくせるほうが大きい)

点検口が誕生し、2度目の宅内工事

点検口が誕生し、3月上旬、2度目の宅内工事が行われた。2度目の宅内工事では、1度目の工事と同じ作業者の方が来てくれた。作業者の方は1度目の工事のことを覚えてくださっていて、半年越しで工事を完了でき、お互いに戦友みたいな感じになった。

ただ、開けてもらった点検口の場所が微妙に良くなかったらしく、結局 IDF への通線は少し苦戦したらしい。

ともあれ、宅内工事が完了した。これが3月初頭。ここまでで5ヶ月半が経過していた。

そして終戦

宅内工事が完了し、残すは屋外工事のみとなった。NURO の屋外工事は長く待たされることで有名だが、私の場合は約1ヶ月半後の 4/22 に行われることとなった。 そして先日 4/22、ついに屋外工事が完了したわけである。

というわけで、VDSL と NURO の速度比較画像をもって本記事の結びとしたい。 なお、開通したプランとしては NURO 光 G2 V(旧: マンションミニ)プランである。

f:id:hitsumabushi845:20210504023218p:plain
VDSL

f:id:hitsumabushi845:20210504023249p:plain
NURO

余談

屋外工事にあたって、管理会社に連絡をしたところ、半年に渡って協力してくれた管理会社の担当の方が異動かなにかで担当を外れてしまっていた。最後にお礼を申し上げたいところだったが、叶わず。

ここでの学び

  • 光配線方式しか勝たん。
  • 半年経つと人は異動する可能性がある

おわりに

というわけで、7ヶ月かけて NURO の通っていない賃貸物件に NURO を開通させることに成功した。管理会社の方を味方につけたことや、(結果としてこの方法は取れなかったが)直接引き込みの検討など、様々なアプローチで NURO 開通へ向けて邁進したことがこの結果に繋がったのではないかと思う。

また会社の slack でこれらの進捗を逐一実況しており、多くの方が見守ってくれたことも支えとなった。開通したときは多くのリアクションをいただけて、ありがたい限り。

f:id:hitsumabushi845:20210504023614p:plain
開通したときのリアクション

『Kubernetes Certified Application Developer (CKAD) with Tests』記録 - セクション3

引き続き、『Kubernetes Certified Application Developer (CKAD) with Tests』を進めていく。
今回は Section 3: Configuration。

Section 3: Configuration

Pre-Requisite - Commands and Arguments in Docker

Docker コンテナのコマンドと引数について。
Dockerfile の CMD, ENTRYPOINT について説明されている。

Docker をちゃんと触ったことないので助かる(そんな状態で Kubernetes に手を出してるのはアレだが...)

Commands and Arguments in Kubernetes

Pod manifest における spec.containers[*].command, spec.containers[*].args フィールドについて、Dockerfile の例と比較して。
commandENTRYPOINT を、argsCMD を上書きする。

Environment Variables

コンテナ内の環境変数について(spec.containers[*].env)。
後段の ConfigMap への布石。

ConfigMaps

あんまり触れてなかったのでちゃんと書く。 env で指定するような key-value pair を外出しできるやつ。
kubectl create configmap で作成したり、

$ kubectl create configmap \
    app-config --from-literal=APP_COLOR=blue \
               --from-literal=APP_MODE=prod

yaml を書いたり。

apiVersion: v1
kind: ConfigMap
metadata:
    name: app-config
data:
    APP_COLOR: blue
    APP_MODE: prod

spec.containers[*].envFrom[*].configMapRef で、ConfigMap を環境変数として注入できる。

ほか、ボリュームとして注入してファイルとして扱うなど。

Secrets

ConfigMap は平文で格納されるが、Secret は Base64エンコードされた状態で格納されるやつ。 kubectl create secret generickubectl create secret tls で作成するか、yaml を書くか。

$ kubectl create secret generic \
    <secret-name> --from-literal=<key>=<value as plain>
$ kubectl create secret generic \
    <secret-name> --from-file=<path-to-file>
apiVersion: v1
kind: Secret
metadata:
    name: <secret-name>
data:
    <key>: <base64 encoded value>

spec.containers[*].envFrom[*].secretRef で、Secret を環境変数として注入できる。 注入したあとはデコードされた値が利用できる。

Docker Security

Docker のプロセス分離について。Namespace でプロセスを分離している。 コンテナ内の実行ユーザーについて。デフォルトは root、--user=xxxdocker run 時に指定したり、Dockerfile の USER フィールドに指定することで異なるユーザで実行できる。 ユーザの権限を操作する場合は、--cap-add, --cap-drop--privileged を使う。

Container Security

k8s におけるコンテナは Pod で抽象化されているため、Pod 単位でのセキュリティ設定が可能。 Pod 単位で設定した場合は、Pod 内の全てのコンテナに反映される。

spec:
  securityContext:
    runAsUser: 1000
  containers:
  ~~

コンテナ単位で設定する場合は、containers 以下に設定する。 コンテナ単位での securityContext では、capabilities を設定でき、ユーザの権限を操作できる。これは Pod 単位ではできない。

Service Account

KSA は認証/認可やRBACに関わってくるけど、CKAD では KSA の使い方だけ分かってればいいらしい。 k8s のアカウントは User Account と Service Account に大別される。

Service Account はアプリケーションが k8s クラスタを操作するためのアカウント。 例えば Prometheus が k8sAPI を叩いてメトリクスを取得する際などに使う。

> kubectl create serviceaccount <serviceaccount name>
> kubectl create sa <serviceaccount name>

describe すると、Token というフィールドが見える。 これは k8sAPI を叩くための認証トークンとクライアント証明書を持った Secret で、KSA を作成すると自動的に作成される。

default という名称の ServiceAccount は各 namespace にはじめから存在する。 そもそも Pod は ServiceAccount と紐付いている必要があり、マニフェストで指定しなかった場合は default が使用される。default SA は権限が弱く、基本的なクエリしか実行できない。 default をマウントさせたくない場合は、spec.automountServiceAccountTokenfalse にする。

異なる ServiceAccount を使用する場合は、Pod マニフェストspec.serviceAccount に明示的に指定する。

Resource Requirements

kube-scheduler はノードのリソース状況(CPU, Memory, Disk)を見ながら最適なノードに Pod をスケジューリングする。

ワークロードの使用するリソースの最低値・最大値を指定するには、spec.containers[*].resources フィールドを使用する。 resources.requests には要求値(最低値)、resource.limits に最大値を指定する。

LimitRange リソースをつかって、resource フィールドを指定しなかった場合のデフォルト値を指定できる。

なお、負荷に応じてワークロードをスケールさせる HPA とか VPA とかは CKAD では範囲外。

Taints and Tolerations

Taint と Toleration は Pod を特定の Node にスケジューリングさせないための仕組み。
これらは、スケジューリングさせないための仕組みであって、Pod を特定の Node にスケジューリングさせるための仕組みは後述する Node Selector や Node Affinity が担う。

Taint は Node に、Toleration は Pod に設定する。 Node に設定された Taint と合致する Toleration が設定された Pod がスケジューリングされる。

Taint は kubectl taint nodes {node name} key=value:taint-effect で設定できる。 key, value が Taint の条件となり、taint-effect でその振る舞いを設定できる。
taint-effect には NoSchedule, PreferNoSchedule, NoExecute がある。

Toleration は、manifest の spec.tolerations に設定される。

Master Node に Pod がスケジューリングされないのもこれのおかげ。

Node Selectors

Pod を特定の Node にスケジューリングさせるための仕組み。 manifest の spec.nodeSelector に、Node に設定したラベルを指定する。

Node にラベルを設定するには、kubectl label nodes {node name} key=value を実行する。

Node Selector では、指定されたラベルへの完全一致のみサポートしているが、OR条件やNOT条件などを利用したいケースがあり、これは Node Affinity でサポートされる。

Node Affinity

Node Selector より柔軟な設定が可能なもの。 spec.affinity.nodeAffinity に設定され、requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredExecution の2種類が設定できる1

required~ は必須条件。マッチする Node がない場合はスケジューリングされない。
preferred~ は推奨条件。マッチする Node がない場合は他の Node へスケジューリングされる。
IgnoredDuringExecution とあるように、実行中の Pod に対してはこの設定は影響せず、例えば nodeAffinity を設定した Pod が実行されている Node から、その nodeAffinity の条件を満たさなくなるようにラベルを削除したとしても、その Pod は削除されない2

かなり柔軟に設定できるため、フィールドがいろいろあって混乱する。 この辺をブックマークして、試験中に見れるようにしておこう。
https://kubernetes.io/ja/docs/concepts/scheduling-eviction/assign-pod-node/
https://kubernetes.io/ja/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/

Taints & Tolerations vs Node Affinity

特定の Node に特定の Pod だけをスケジューリングさせたい場合は、Taints/Tolerations と Node Affinity を併用しようねという話。


Section 3 はここまで。ちょっと忘れちゃいそうな点がままあるので、折に触れて復習していこうと思う。


  1. 将来的に requiredDuringSchedulingRequiredDuringExecution が提供される予定。

  2. 当然、requiredDuringSchedulingRequiredDuringExecution の場合は削除される。