Kubernetesのカスタマイズポイントのまとめ
※ この記事は2019年03月23日に別のサイトで公開していたものをコピーしたもので、最新のKubernetesに対応している保証はありません
インフラエンジニアがKubernetesを使って自社の基盤を設計する上で気になるのは「Kuberneretesが自社の要件にフィットするのかどうか」です。 そういった時のためにKubernetesは拡張可能なポイントを数多く備えています。 この記事では現時点で最新のKubernetes v1.13のカスタマイズ可能なポイントを整理して自社の要件に必要な機能をKubernetesに持たせることができるのかどうかを考えるための情報をまとめます。
なお、この記事で扱うのはAPIリクエストのカスタマイズの方法であり、ネットワークやストレージまわりのカスタマイズは対象としません。 通信のパフォーマンスやデータのバックアップ、リストアについて検討されている方はCNI(Container Network Interface)やCSI(Container Storage Interface)のドキュメントをご覧ください。個人的にはCSIを使った実装の一つであるRookに注目しています。
KubernetesのAPIリクエストのフロー
まず、カスタマイズをする前のKubernetesの基本的な処理の流れを確認します。KubernetesはRESTfullなAPIで設計されており、Masterで立ち上がっているAPI ServerがKubernetesの各種リソースに対するリクエストを受け付けています。
Kubernetesのアーキテクチャはとてもシンプルで、ユーザがkubectlを実行すると対象のリソースの操作内容に対応するAPI Serverのエンドポイントにリクエストが送られます。 API Serverの役割はリクエストのヘッダを確認して認証と認可を実施したあと、受け取ったリクエストをetcd上に保存することです。Kuberbernetesは各種リソースに対応するControllerがetcdを監視しており、コンテナの作成やServiceの作成、変更などの実際のアクションはControllerがetcd上のデータの追加や変更を検知して実行します。 このように、あるべき姿を定義した上でControllerが状態の変化を監視し、変化があれば対応する処理を実施することをReconciliation loopと呼びます。
カスタマイズ機能の分類
Kubernetesにどんなことがカスタマイズできるのかを調べるということは、ユーザがリクエストを送ってからetcdにリソースの定義を書き込むまでの間にどのような情報を付与するか、またはオリジナルのリソースとそれに対応するControllerを定義するか、あるいはそのどれでもない完全に独自の仕組みを作るかに分類できます。
それぞれの選択肢には明確な違いがあり、API Serverのリクエストを補完する拡張やAPI ServerのAPIエンドポイントを増やす拡張、Kubernertesが想定する枠組みをほとんど使わない方法があります。
大まかに分類すると以下の通りです。
手法 | 説明 |
---|---|
Admission Controller | API Serverに対するリクエストの認証。認可を済ませたあとにそのリクエストをハンドルする拡張。様々な種類がある。どの拡張を実施するかはKubernetesクラスタ構築時に指定する |
Custom Resource Definition | API Serverに新しい種類のリソースを登録する。リソースの定義や振る舞いは独自に定義できる。クラスタ構築後でもサービスを停止することなく追加可能 |
Aggregated API Server | k8sのAPI Serverの基本プロトコルでは実現できない処理を実現するための専用のAPI Serverを別途用意する拡張 |
なお、最近のKubernetesの流行として押さえておくべきトピックとしてOperatorがあります。OperatorはCustom Resorce Definition(通称CRD)のうち、特定のアプリケーション、ミドルウェアに特化したものです。Operatorは特定のツールを抽象化するための強力な仕組みです。
例えば、ビッグデータのインメモリ分散処理フレームワークのApache SparkがKubernetesをサポートしたすぐ後にGoogleがApache SparkのためのOperatorを公表しました。Spark Operetorがデプロイされたk8sクラスタであれば、以下のマニフェストを使ってKubernetesにリクエストを投げることでSparkジョブを実行することができます。
apiVersion: sparkoperator.k8s.io/v1beta1 kind: SparkApplication metadata: name: spark-pi namespace: default spec: type: Scala mode: cluster image: gcr.io/spark/spark:v2.4.0 mainClass: org.apache.spark.examples.SparkPi mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar
もしもKubernetes上で特定のアプリ、ミドルウェアを使うことがあるのであれば、対応するOperatorが公開されているかを調べてみるのもいいかもしれません。
ただし、Operatorは想定した動作を簡単なyamlを使って実行するための仕組みです。普段の作業をテンプレートに落とし込めるので正常系の処理は楽になりますが、障害が発生したときはそのアプリやミドルに詳しい人が必要であることには変わらないので、Operatorがあれば運用の全てが解決するわけではないことは忘れないようにしましょう。
例えばorg.apache.spark.examples.SparkPi以外のSparkアプリケーションを実行すると毎回SparkのMasterのPodがOOMで死ぬといった場合はOperatorが対処できる範囲外で、spark.driver.memory
を見直してDriverに割り当てるメモリを増やすなどSparkの知識を必要とするチューニングが必要になります。
Admission Controller
Admisstion Controllerは最もシンプルで簡単なカスタマイズ手法です。 ユーザからリクエストを受けとったAPI Serverが認証と認可を済ませた後に、そのリクエストに含まれるパラメータを差し替えたり認可とは別に実行そのものを許可するかどうかを制御することができます。 Kubernetesがあらかじめ用意している複数のポリシーから選択してAPI Serverに設定することができます。
Kubernetes v1.13時点では以下がデフォルトで設定されています。
NamespaceLifecycle
,LimitRanger
,ServiceAccount
,PersistentVolumeClaimResize
,DefaultStorageClass
,DefaultTolerationSeconds
,MutatingAdmissionWebhook
,ValidatingAdmissionWebhook
,ResourceQuota
,Priority
API Server起動時に--enable-admission-plugins
オプションにカンマ区切りで書くことで他のAdmission Controllerの追加や削除をすることができます。
Admission Controllersは数が多いのでここでは個別の説明は省きます。 詳細を知りたい方は以下のリンク先にそれぞれの説明がありますので参照してください。
https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
Custom Resource Definition
Custom Resource Definition(CRD)はAPI Serverに新規のエンドポイントを登録するための仕組みです。新しいリソースの定義をCRDとして登録すると、API Serverにそのリソースのエンドポイントを新規に追加することができます。
CRDだけではAPI Serverにリクエストのエンドポイントを追加することしかできません。追加したリソースの挙動はそのリソースのCRDに対応するCustom Resource Controllerが決定します。 このControllerは自分で実装した上でKubernetesクラスタ上にデプロイする必要があります。 デプロイされたContollerは独自のロジックに従い対応するリソースに対してReconciliation loopを実行していきます。
Custom Resource DefinitionとCustom Resource Controllerを実装するためのSDKの例として以下があります。
- kubebuilder
- Operator SDK
- Metacontroller
余談ですが、通常だと1つのリソースに対して1つのControllerが存在するのですが、PodやDeploymentなどデフォルトで利用可能なリソースのControllerはKubernetesクラスタ構築時にkube-controller-managerという名前で1つのPodとしてデプロイされています。
Aggregated API Server
Aggregated API ServerはKubernetesの標準コンポーネントであるAPI Serverではなく新しく用意する別のServerで処理を実現するための仕組みです。 API Serverはユーザから受け取ったリクエストを処理する機能を持つことはこれまで説明してきましたが、実はその処理を他のServerを委譲する抽象化レイヤを持っています。 デフォルトのAPI Server以外にユーザから受け取ったリクエストを処理するAPI ServerをAggregated API Serverといいます。 Aggregated API Serverの例としてmetrics serverやservice catalogがあります。
Aggregated API Serverが登録されているAPI Serverはユーザのリクエストの認証と認可を済ませると該当する処理をAggregated API Serverに丸投げします。 Aggregated API Serverは受け取ったリクエストを内部で処理し、結果をAPI Serverと通じてユーザに返します。 Custom Resource DefinitionではAPI Serverが全ての処理を実施した上でReconcilation loop処理を実施していましたが、Aggregated API Serverではさらにその前でhookすることが可能になるため自由度はCustom Resource Definitionよりも高いです。
Aggregated API Serverを実装するためのSDKとしてapiserver-builderが用意されています。
カスタマイズ手法の比較
手法 | 追加実装 | 拡張の自由度の高さ |
---|---|---|
Admission Controller | 不要 | 低い |
Custom Resource Definition | 必要 | ある程度制約があるが比較的自由 |
Aggregated API Server | 必要 | ほとんど制約がなく自由 |
導入を検討する場合はまず最初に使えるAdmission Controllerがないかを調査し、必要な機能が不足していると感じればCustom Resource Definitionを検討し、それでも駄目ならAggregated API Serverを採用する順番がおすすめです。 自由度の高さはそのまま運用コストと利用方法を普及するコストの増加につながりますので、運用者が少ない場合はできるだけAdmission Controllerの利用に留めるのが正解です。
資料
【サイバーエージェント&ニフクラ】春の Kubernetes 祭り! @銀座 にて上に書いている内容を図にしてまとめて発表しました。
スライドはSpeakerDeckにて公開しておりますのでぜひそちらもご覧ください。
Docker Meetup #27参加報告
Docker Meetuo#27の参加報告
ざっと見て19:00の段階で8割の席は埋まっている
KubeCon 報告1: コンテナランタイムやFirecrackerの話題ひととおり振り返ってみよう (Container runtimes & Firecracker Recap) Kohei Tokunaga
- 2018年はコンテナランタイム群雄割拠の年
- KubeConで出てきたコンテナランタイムに関する話題を全て紹介する
- k8sランタイムとセキュリティ
- コンテナ内からの脅威とコンテナ外からの脅威に分けられる
- コンテナ内からの攻撃は現実には存在しないが、そのうち発生してくると予想されている
- 何をすればいいか
- 脆弱性をなくすこと
- 権限に制限を加える
- コンテナが影響を与える範囲を狭める
- これらはランタイムによって実現可能
- Kubernetesセキュリティチームは脆弱性があってもgithubのissueで報告してはいけないというルールになっている
- dockerdは拡張性の高さが特徴
- cri-o
- Kubernetes criのミニマム実装
- podman
- 軽量かつrootlessなのが特徴
- kata containers VS gVisor
- kata VS Nable
- Nabla
- 7種類のシステムカールのみを発行しており、バグを踏みにくいと主張
- Nabla
- Firecrackerのミーティングが場外で行われたので参加してきた
- 軽量VMでコンテナを隔離
- 現状ではOCIやCRIには準拠していないが、Kataやcontainerdと統合してKubernetes上で使えるようになりつつある
- containerdのプラグインの一つとして振る舞う
- 感想
- 自分の環境にどのランタイムが判断できる人ってどれだけいるんだろう
KubeCon 報告2: About kanister Makoto Hasegawa
- 資料: https://speakerdeck.com/makocchi/kubecon-cncon-2018-recap-about-kanister
- 管理者からみるとランタイムは動かしてみると面白いよ
- Kanisterの話をする
- CI/CD, Kubernetes, and Databases: Better Togethe の話
- Cloud Nativeな環境でDBを動かすのは難しい
- アプリと隔離されており、ペットとして扱われている(家畜じゃないよ、ペットだと、という意味)
- DB専属のエンジニアが必要になってくる
- 全部 CI/CDに組み込んで自動化できれば幸せになるはず
- Kanister(燃料缶の意味)があればそれができるよとのこと
- data capster/export
- SCI対応でblock storageなどにファイルをdumpできるし、S3にアップロードもできる
- database manipulation
- fileterやマスキングか可能になる予定
- CRDを使った処理などKubernetesと密接したDBのコントロールが可能
- kanisterが対応しているもの
- mondofb
- mysql
- postgresql
- elasticsearch
- kanister blueprintが肝だと思っている
- taskを定義したCRDで、コミュニティに広がれば誰もが恩恵を得られるようになる
- data capster/export
- Kanisterはhelmでインストールできる
- productionクラスタとtestクラスタそれぞれでDBを用意して、cloud storageを介してデータをやり取りしながら検証するデモ
- 異なるnamespaceに同じ内容のDBを構築したりすることもできるようになる
Docker Compose-on-Kubernetes Kunal Kushwaha
- docker-composeの役割の紹介
- compose on kubernetesの話へ
- https://github.com/docker/compose-on-kubernetes
- etcdに専属のCompose API Serverが書き込むアーキテクチャになっていたけれど、このetcdはCompose用に別途用意するものらしい
docker stack
コマンドでkubernetesにデプロイするデモ- 感想
- dockerだけを使っていた人があとからkubernetesに移行するときに便利
- Daplyomentのサポートはあるけど、Jobのサポートがあるか気になる
DockerのCUIツール作った話 @gorilla0513
- 資料: https://docs.google.com/presentation/d/1ty9MbOGT8HThYVC1DVZtmhKS5MyCNGkDdkCTs6vpqzk/edit#slide=id.p
- こんなのを作った:https://github.com/skanehira/docui
- 初心者の人に便利な機能を用意したかった
- 作ったモチベーション
- Goを勉強したい, コマンド操作がめんどくさい、ターミナルから抜けたくない
- 作ったとき大変だったこと
- 人に使ってもらえることや形になるまで作りたくてモチベーションを維持していった
- 開発にしてくれる人を募集中
- 感想
- 熱意で業務に関係がないツールを作りきったのすごい
CNAB: Cloud Native Application Bundle Kohei Ota
- CNAB: 分散アプリをパッケージングする企画
- MicrosoftとDocker者が主体となって開発を進めている
- Cloud Nativeはいろいろコンポーネントがあり、それぞれの学習コストが高い
- CNABの基本構成
- bundle,json: CNABのバージョンやイメージ等
- app/Dockerfile:
- run:
- DuffleというCLIでCNABで管理しているアプリを操作する
- goで書いてるのにgo getじゃ落ちてこないなどハードルが高め
- Docker-appもCNABをサポートしている
- https://github.com/docker/app
- 2018年にDocker社がリリースしたエコシステム
- docker-composeだと環境ごとの差分を扱うのが大変なので用意されたもの
- Duffleのdemo
- DuffleのREADME.mdに書かれているコマンドを順番に実行
- 感想
- 分散アプリと聞いてHadoopみたいなものの管理ツールかと思ったけれど、単にKubernetesのパッケージングツール?
- 今回のデモの範囲だとhelmとの違いがよくわからなかった
LT 1: GitLab Serverlessとその中身(KubeCon 報告LT) Takuya Noguchi
- AWS Lambdaがあるけどベンダ非依存でサーバレスを使いたいよねという人向けにKnativvveが出てきた
- Gitlab ServerlessはKubecon Seattle中にalpha版としてリリース
- Knative
- Istioを含むヘビーな子
- RedHat, アイビーエムgあサポート開始
- Gilab Serverlessを使う手順
- Kubernetesと連携
- TrigerMesh CLI
- tmコマンド で操作
LT 2: kubectlを実行してからetcdに書き込むまでに @yosshi_
- 資料: https://speakerdeck.com/yosshi_/what-happens-when-dot-dot-dot-kubectl-run-nginx-image-nginx-replicas-3
- kubectlの動き気になりませんか
- kubectlのソースを読むしかないが敷居が高い
- そんな人向けに神ドキュメントがある
- 目次を見るだけで処理の流れがわかる
- このドキュメント読んでからコードを読むと理解しやすい
- ときどきリンク切れがあるけどそこは気にしない
- なぜkubectl runでデフォルトでdeploymentとして動くかなどがわかる
- 電車の中で読むとQOLが上がるよ
LT 3:Rancher’s New Mluti-Tenant Prometheus Support Yutaka Ichikawa
- 資料: https://qiita.com/cyberblack28/items/8a1dbd26aef8a85e6b8e
- コンテナベースオーケストレーションの本の6章を担当、増刷決まりました
- KubeConではMySQL OperatorやVittesが面白かった
- Rancher 2.2で組み込まれるPrometheusの話をする
- Prometheusはalpha版
- カタログの機能としてGrafanaとPrometheusをそれぞれカタログが用意されていたが、それらのデプロイがさらに簡単になった
- Monitoringというボタンを押して、Prometheusを選択してSaveするだけ
- 各種方法は公式のBlogに書いてあるので読んでね
LT 4: JKDv18.12でCFP採択までに考えたこと Ryoma Fujiwara
- 大きいイベントで話をしたいと考えてる人の背中を後押しするのが目的の発表
- 考えたこと
- 求められていることはなにか
- 実感、共感を持ってもらう話をするには?
- 求められていること
- 例えば個別技術の細かい話だが、自分はOSSのメンテナでもないので、無理だと思った
- そこで、沿い文の取り組みを知ってもらったり、何かを得てもらい、行動や判断にいい影響を与えたい
- ユーザ企業にしか話せないことを考え、プロダクト開発で技術的にぶつかった課題やみんなが直面するであろう課題について話しをすることにした
- 実感、共感を持ってもらう話をするには?
- キラキラした話は実感をもってもらいにくい
- そこで、実際に問題にぶつかった人に話してもらうのがいいと思い、いろんな担当者に登壇してもらうことにした
- 発表することになると、正しいことを話すために調べて新しい知識を得られる
- 予告: CloudNativeDays TokyoのCFPを近いうちに募集します
ラズパイクラスタにKubernetesをインストール(成功編)
「ラズパイクラスタにKubernetesをインストール(失敗編)」でCentOSを選んだためDockerのインストールに失敗したので、今度はUbuntuで試してみる。
今回の作業内容
全体の作業概要
- 物理的な配線(ラズパイでKubernetesクラスタを構築する(物理編))
- ラズパイにOSをインストール(本記事の範囲)
- Kubernetesのインストール(本記事の範囲)
- Dockerをインストール
- cgroupでmemoryサブシステムを有効にする
- Kubernetesのインストール
Dockerをインストールしようとすると依存関係のエラーが出て、その解決方法を調べるのに時間がとられた。
OSイメージをMicroSDに焼く
UbuntuのwikiからOSイメージをダウンロードする。
公式イメージはPi2用しか配布されていないのでPi3にインストールするためには一手間が必要になる。一応Unofficialとして個人が公開しているPi3用のイメージへのリンクがwikiに貼られている。
いろいろ面倒そうなので公式イメージを使うことにした。
ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img.xzをMacにダウンロードしてxzコマンドで解凍する。
$ xz -d ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img.xz $ ls ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img
MicroSDカードをUnMountしてからSDカードへ書き込む。1枚書き込むのにだいたい30分かかる。
$ diskutil unmountDisk /dev/disk2 Unmount of all volumes on disk2 was successful $ sudo dd bs=1m if=./ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img of=/dev/disk2 2252+0 records in 2252+0 records out 2361393152 bytes transferred in 1949.493602 secs (1211285 bytes/sec)
このOSイメージはPi2用なので、Pi3用で動かすためには
- dbtファイルの置き換え
- config.txtの書き換え
が必要。
また、Pi3 B+で動かすためにはさらにbootloader用にbootcode.bin, fixup.dat and start.elfを置き換える必要がある。
dbtファイルを含めて必要なファイルはGithubのraspberrypi/firmwareリポジトリで公開されている。
wgetでダウンロードする。
$ wget https://github.com/raspberrypi/firmware/raw/master/boot/bcm2710-rpi-3-b-plus.dtb $ wget https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin $ wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat $ wget https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
MicroSDカードが/Volume/system-boot
にマウントされているとして、ダウンロードしたファイルをコピーする
$ cp bcm2710-rpi-3-b-plus.dtb /Volumes/system-boot/ $ cp start.elf /Volumes/system-boot/ $ cp bootcode.bin /Volumes/system-boot/ $ cp fixup.dat /Volumes/system-boot/
次に、/Vomue/system-boot/config.txt
の中身を以下のように変更する。
# For more options and information see # http://www.raspberrypi.org/documentation/configuration/config-txt.md # Some settings may impact device functionality. See link above for details # コメントアウト #kernel=uboot.bin #device_tree_address=0x02000000 # 追記 kernel=vmlinuz initramfs initrd.img followkernel
終わったらSDカードを取り出す。
$ diskutil eject /dev/disk2 Disk /dev/disk2 ejected
OSをインストールする
MicroSDカードを刺した状態で電源をいれるとOSのインストールが始まる。
ログインプロンプトが表示されたら
アカウント名:ubuntu
パスワード: ubuntu
でログインしてすぐにパスワードの初期化を求められるので実施する。
- ホスト名の設定: hostname XXX
続いて、ネットワークの設定をしてパッケージを更新する。
- eth0にアドレスを割り当てる
eth0へのネットワークの割り当てはsudo dhclient eth0
でできる。
続いて、パッケージを更新する。
sudo apt update
sudo apt upgrade -y
- 途中、
keyboad-configuration
の設定を聞かれる.
- 途中、
上記を3台に実施する。
ホスト名とIPアドレス、それぞれの役割は以下の通り。
ホスト名 | IPアドレス | 役割 |
---|---|---|
compute-0-0 | 192.168.10.109 | KubernetesのMaster |
compute-0-1 | 192.168.10.108 | KubernetesのNode1 |
compute-0-2 | 192.168.10.107 | KubernetesのNode2 |
このままだとネットワークの名前解決ができないので、各ホストの/etc/hosts
に以下の内容を追記する。
192.168.10.109 compute-0-0 192.168.10.108 compute-0-1 192.168.10.107 compute-0-2
Dockerのインストール
インストールしたUbuntuはarmhf(32bit版)として動作している。docker-ceの推奨は64bitだがUbuntuであればarmhfをサポートしているので問題ない。
$ sudo apt-get update $ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ software-properties-common $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # armv7lなのでarmhfアーキ用を実行 $ sudo add-apt-repository \ "deb [arch=armhf] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" $ sudo apt-get update $ sudo apt-get install docker-ce $ docker --version Docker version 18.09.0, build 4d60db4
ubuntuユーザがdockerコマンドを実行するたびにsudoが必要である。
sudoがなくてもdockerコマンドを実行できるようにubuntuユーザをdockerグループに追加しておく。
$ sudo gpasswd -a ubuntu docker Adding user ubuntu to group docker $ sudo systemctl restart docker
なお、依存関係のエラーでdocker-ceのインストールに失敗することがあった。
その場合はapt-utilの依存関係を修復する。
$ sudo apt-get install docker-ce Reading package lists... Done Building dependency tree Reading state information... Done You might want to run 'apt --fix-broken install' to correct these. The following packages have unmet dependencies: apt-utils : Depends: apt (= 1.6.3) but 1.6.6 is to be installed docker-ce : Depends: docker-ce-cli but it is not going to be installed Depends: containerd.io but it is not going to be installed Recommends: aufs-tools but it is not going to be installed Recommends: cgroupfs-mount but it is not going to be installed or cgroup-lite but it is not going to be installed Recommends: pigz but it is not going to be installed Recommends: libltdl7 but it is not going to be installed E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution). $ sudo apt --fix-broken install Reading package lists... Done Building dependency tree Reading state information... Done Correcting dependencies... Done The following additional packages will be installed: apt-utils The following packages will be upgraded: apt-utils 1 upgraded, 0 newly installed, 0 to remove and 89 not upgraded. 16 not fully installed or removed. Need to get 0 B/192 kB of archives. After this operation, 0 B of additional disk space will be used. Do you want to continue? [Y/n] Y ...
修復が完了したらもう一度docker-ceをインストールする。
$ sudo apt-get install docker-ce Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce-cli libltdl7 pigz The following NEW packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce docker-ce-cli libltdl7 pigz 0 upgraded, 7 newly installed, 0 to remove and 89 not upgraded. 1 not fully installed or removed. Need to get 29.7 MB of archives. After this operation, 149 MB of additional disk space will be used. Do you want to continue? [Y/n] Y ...
Kubernetesをインストールする
Kubernetesは1.8からSwapが有効になっているとkubeletが起動しなくなっている。 今回の環境はSwap領域は存在しないので気にしてくていいが、もしSwapが有効になっていれば無効化が必要。
# swap領域が0になっている $ free -h total used free shared buff/cache available Mem: 923M 138M 84M 4.4M 701M 764M Swap: 0B 0B 0B # 念のためSwapの有無を確認 $ swapon -s
続いて、公式ドキュメントに従って全ホストでkubeadm, kubelet, kubectlをインストールする。
# rootになる sudo su - apt-get update && apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectl
インストールしたパッケージのバージョンを確認する。
# dpkg -l |grep kube ii kubeadm 1.13.1-00 armhf Kubernetes Cluster Bootstrapping Tool ii kubectl 1.13.1-00 armhf Kubernetes Command Line Tool ii kubelet 1.13.1-00 armhf Kubernetes Node Agent ii kubernetes-cni 0.6.0-00 armhf Kubernetes CNI
続いて、Kubernetesクラスタのネットワークを設計する。
Kubernetesはoerlay networkを構築する必要がある。そのためのツールとして有名なところではflannnel, weave, Calicoなどがある。
今回はARMプロセッサの上で動くUbuntu 18.04の32bit版で動作することが要件になる。
Calicoの要件はAMD64プロセッサであること。Ubuntuの32bitで動作するか不安なので見送る。
WeaveはARMをサポートしたバイナリをリリースしているものの、32bitに対応しているか明記されていなかったこととWeaveをラズパイ3B+で動かしたときにカーネルに起因するバグがあるissueを見つけたので見送る。
そこで、今回はflannelを採用することにした。
先ほど書いたようにホストは192.168.10.0/24で設定されている。
flannelが環境構築のために公開しているマニフェストは初期値が10.2544.0.0/16になっている。Pod IPのCIDRは10.244.0.0/16を割り当てることにした。違うCIDRを割り当てたい場合は、後述するflannelの環境構築時にgithub上のマニフェストを指定するのではなく、ローカルにダウンロードしたマニフェストを編集して利用すればいい。
KubernetesのMasterを起動するため、compute-0-0でkubeadm init
を実行する。
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 [init] Using Kubernetes version: v1.13.1 [preflight] Running pre-flight checks [preflight] The system verification failed. Printing the output from the verification: KERNEL_VERSION: 4.15.0-1017-raspi2 CONFIG_NAMESPACES: enabled CONFIG_NET_NS: enabled CONFIG_PID_NS: enabled CONFIG_IPC_NS: enabled CONFIG_UTS_NS: enabled CONFIG_CGROUPS: enabled CONFIG_CGROUP_CPUACCT: enabled CONFIG_CGROUP_DEVICE: enabled CONFIG_CGROUP_FREEZER: enabled CONFIG_CGROUP_SCHED: enabled CONFIG_CPUSETS: enabled CONFIG_MEMCG: enabled CONFIG_INET: enabled CONFIG_EXT4_FS: enabled CONFIG_PROC_FS: enabled CONFIG_NETFILTER_XT_TARGET_REDIRECT: enabled (as module) CONFIG_NETFILTER_XT_MATCH_COMMENT: enabled (as module) CONFIG_OVERLAY_FS: enabled (as module) CONFIG_AUFS_FS: enabled (as module) CONFIG_BLK_DEV_DM: enabled DOCKER_VERSION: 18.09.0 OS: Linux CGROUPS_CPU: enabled CGROUPS_CPUACCT: enabled CGROUPS_CPUSET: enabled CGROUPS_DEVICES: enabled CGROUPS_FREEZER: enabled CGROUPS_MEMORY: missing [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 error execution phase preflight: [preflight] Some fatal errors occurred: [ERROR SystemVerification]: missing cgroups: memory [preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
cgroupのmemoryが無効化されているらしい。/proc/cgroups
を確認するとたしかにmemoryのenabledが0(無効)になっている。
$ cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 10 2 1 cpu 6 60 1 cpuacct 6 60 1 blkio 7 60 1 memory 0 68 0 devices 4 60 1 freezer 2 2 1 net_cls 3 2 1 perf_event 5 2 1 net_prio 3 2 1 pids 8 66 1 rdma 9 1 1
boot時の設定を変更してcgroupfsのmemoryを有効にする。
/boot/firmware/cmdline.txt
にcgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
を追記して再起動する。追記が終わったあとのファイルは以下の通り。
$ cat /boot/firmware/cmdline.txt net.ifnames=0 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory # reboot
再起動したあとはeth0に割り当てられたIPが消えているのでsudo dhclient eth0
を実行する。
memoryサブシステムが有効になっているのがわかる。
$ cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 2 1 1 cpu 5 34 1 cpuacct 5 34 1 blkio 4 34 1 memory 7 68 1 devices 11 34 1 freezer 9 1 1 net_cls 3 1 1 perf_event 8 1 1 net_prio 3 1 1 pids 6 39 1 rdma 10 1 1
再度Kubernetesをインストールしなおす.
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 [init] Using Kubernetes version: v1.13.1 [preflight] Running pre-flight checks [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Activating the kubelet service [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [ubuntu kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.10.109] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [ubuntu localhost] and IPs [192.168.10.109 127.0.0.1 ::1] [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [ubuntu localhost] and IPs [192.168.10.109 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [kubelet-check] Initial timeout of 40s passed. [apiclient] All control plane components are healthy after 85.513804 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.13" in namespace kube-system with the configuration for the kubelets in the cluster [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "ubuntu" as an annotation [mark-control-plane] Marking the node ubuntu as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node ubuntu as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: ntvqxo.ghxfq7gvi8rc79aw [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes master has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 192.168.10.109:6443 --token ntvqxo.ghxfq7gvi8rc79aw --discovery-token-ca-cert-hash sha256:709766a97f016e2a0fd5113b12ce5afa1cebc740ecfa6596f8bbe9f30cb5897f
kubectlに認証設定を読み込ませるために指定されたコマンドを実行する。
$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
動作していることが確認できる。
$ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-0 NotReady master 23m v1.13.1
STATUSがNodeReadyなのはOveray Networkが設定されていないから。flannelをインストールする。
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.extensions/kube-flannel-ds-amd64 created daemonset.extensions/kube-flannel-ds-arm64 created daemonset.extensions/kube-flannel-ds-arm created daemonset.extensions/kube-flannel-ds-ppc64le created daemonset.extensions/kube-flannel-ds-s390x created # STATUSがReadyになった $ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-0 Ready master 34m v1.13.1
Nodeになるcompute-0-1とcompute-0-2で以下を実行する。
$ sudo kubeadm join 192.168.10.109:6443 --token ntvqxo.ghxfq7gvi8rc79aw --discovery-token-ca-cert-hash sha256:709766a97f016e2a0fd5113b12ce5afa1cebc740ecfa6596f8bbe9f30cb5897f [preflight] Running pre-flight checks [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 [discovery] Trying to connect to API Server "192.168.10.109:6443" [discovery] Created cluster-info discovery client, requesting info from "https://192.168.10.109:6443" [discovery] Requesting info from "https://192.168.10.109:6443" again to validate TLS against the pinned public key [discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "192.168.10.109:6443" [discovery] Successfully established connection with API Server "192.168.10.109:6443" [join] Reading configuration from the cluster... [join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Activating the kubelet service [tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap... [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "compute-0-1" as an annotation This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the master to see this node join the cluster.
compute-0-0からkubectl get node
を実行するとNodeがクラスタとして認識されていることを確認できる。
$ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-2 Ready <none> 73s v1.13.1 compute-0-1 Ready <none> 75s v1.13.1 compute-0-0 Ready master 39m v1.13.1
以上でKubernetesクラスタの構築ができました。
CentOSのコンテナを作ってみる。
$ kubectl run tmp-centos --rm -it --image centos -- bash 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. If you don't see a command prompt, try pressing enter. [root@tmp-centos-cc49649b6-kpfvg /]#
Deploymentが動くことも確認できた。
まとめ
Kubernetesクラスタのインストールは何度もやったことがあったので、初のラズパイといってもまぁすぐに終わるだろうと思っていたら、実家のネットワーク設定によるものやSDカードの不具合によるもの、OSの選定、OSインストール後の謎の個体差などなどでかなり時間がかかってしまった。
他にも実はここに書ききれない細かなトライ&エラーを繰り返している。Ubuntu 18系を使うのは初めてだったので、原因がOSのバージョン、カーネルのバージョン、ラズパイのどれに起因するものなのかの切り分けが大変だった。
トラブルの原因を調べて解決することを繰り返すことで知識がつくので、これはこれで新年からいい経験ができたと思う。
参考サイト
ラズパイクラスタにKubernetesをインストール(失敗編)
この記事はラズパイでKubernetesクラスタを構築する(物理編)の続きにあたる。
OSの選定を間違ってしまい作業が詰んだので失敗編としてまとめることにした。
正しい手順はラズパイクラスタにKubernetesのインストール(成功編)にまとめる。
OSとDockerのインストール
ラズパイ初心者なのでインストール可能なOSを一通り把握しておきたい。
Raspberry Pi で動く様々なOS一覧まとめ13種類!という2018.11.19の記事を読んでベーシックなRaspbianと普段業務で使っているCentOSで迷ったが、今後実際に使っていくことを考えるとKubernetesとして利用事例が多いCentOSを採用することにした。(そしてこれが失敗編を書くことになった理由である)
OSイメージをダウンロードする。 ラズパイのCPUはarmなので候補の一覧からarm向けを調べCentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1810-sda.raw.xzというラズパイ向けのminimalイメージをダウンロードした。
解凍にはxzコマンドが必要。brewでインストールする。
$ brew install xz
解凍する。
$ xz -d CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1810-sda.raw.xz $ ls CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1810-sda.raw
続いて、このイメージファイルをddコマンドでMicroSDカードに書き込む。
USB Type-C ハブを使ってMacにMicroSDカードを接続。
認識したディスクをdiskutilで調べると/dev/disk2
で認識されている。
$ diskutil list /dev/disk0 (internal): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme 500.3 GB disk0 1: EFI EFI 314.6 MB disk0s1 2: Apple_CoreStorage Macintosh HD 499.3 GB disk0s2 3: Apple_Boot Recovery HD 650.0 MB disk0s3 /dev/disk1 (internal, virtual): #: TYPE NAME SIZE IDENTIFIER 0: Apple_HFS Macintosh HD +499.0 GB disk1 Logical Volume on disk0s2 EF1D93DE-2460-4A71-B9DD-9C2223020689 Unlocked Encrypted /dev/disk2 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *31.5 GB disk2 1: Windows_FAT_32 31.5 GB disk2s1
SDカードをUnMountしてからSDカードへ書き込む。1枚書き込むのにだいたい40分かかる。
$ diskutil unmountDisk /dev/disk2 Unmount of all volumes on disk2 was successful $ sudo dd bs=1m if=./CentOS-Userland-7-armv7hl-RaspberryPI-Minimal-1810-sda.raw of=/dev/disk2 2712+0 records in 2712+0 records out 2843738112 bytes transferred in 2440.917174 secs (1165029 bytes/sec) # ディスクの取り出し $ diskutil eject /dev/disk2 Disk /dev/disk2 ejected
なお、購入したUSB Type-C ハブは接続中Wifiが使えなくなったので、調べ物をしたくなるたびにケーブルを抜く必要があった。
配線済みのラズパイクラスタにOSを書き込んだSDカードを差し込む。しかしディスプレイに何も表示されない。どうやら電源ケーブルを刺した状態で後からSDカードを差し込んでも認識しないらしい。一度USBを抜いてもう一度刺し直すと認識しだした。
しばらくするとログインプロンプトが出てくる。
初期アカウント: root
初期パスワード: centos
でログインする。
続いて以下を実行。
- 各種パッケージをアップデート:
yum update -y
- 日本語配列を受け付けるように変更:
localectl set-keymap jp106
- 初期パスワードを変更:
passwd
- ホスト名の設定:
hostname XXX
df -h
を実行すると32GBのMicroSDを使っているにもかかわらずCentOSは2.7GB程度しか認識していない。
df
とfdisk -l
で確認すると、/dev/mmcblk0
がMicroSDカード本体で、これが3つのパーティション/dev/mmcblk0p1
,/dev/mmcblk0p2
,/dev/mmcblk0p3
で区切られており、この3つの合計が2.7GBほどだった。
ここで問題になったのは/
がマウントしている/dev/mmcblk0p3
には1.4GBしか割り当てられておらず、そのうち1.2GBがすでに使われてしまっていること。このままではKubernetesをインストールできない。
そんな時、/root/README
に参考になる情報があると書かれているサイトを見つけた。
開いてみると以下の内容であった。
# cat /root/README == CentOS 7 userland == If you want to automatically resize your / partition, just type the following (as root user): rootfs-expand
どうやらパーティションを拡張するためのコマンドが用意されているらしい。
manを実行しても何もでなかったのでrootfs-expand --help
と適当に叩くとオプションが無視されそのまま実行されてしまい慌てたものの、実行が完了すると/
が28GBに拡張された。
つづいて、Dockerをインストールする。
Dockerの公式ドキュメントでCentOS向けのインストールガイド通りに従いdocker-ce用のリポジトリを追加してyumでインストールしようとするとhttps://download.docker.com/linux/centos/7/armhfp/stable/repodata/repomd.xml: [Errno 14] HTTPS Error 404 - Not Found
が返ってくる。
armhfp向けのパッケージが存在しないようだ。
代わりに、ラズパイ公式サイトの手順に従い以下のコマンドでインストールする。
curl -sSL https://get.docker.com | sh
すると、今度はEither your platform is not easily detectable or is not supported by this installer scrypt.
のエラーになった。
Docker CEのドキュメントを見ると、CentOS向けのDocker CEはARM64 / AARCH64
をサポートしているがARM
(32bit版)をサポートしていないとのこと。
どうやらOS選定の段階で詰んでしまった様子。
OSを32bitでも対応しているDebian系(Rassbianとか)に変えるか、CentOSにこだわるのであればラズパイで動かせる非公式の64bit版のOSイメージをいれるしかない(一応見つけることはできた)。
どうにかならないかと調べたところ、Raspberry Pi 3B系の 64bitモードに対応している OSの一覧まとめ 2018年版というサイトを見つけた。
これによると先ほどのサイトに書かれていなかったUbuntu 18.04も動かせるらしい。これなら32bit版でも64bit版でもdocker-ceをインストールできそうである。MicroSDカードの作り直しから実施して今度こそKubernetesのインストールを成功させる。
MicroSDをフォーマットする
OSを入れ直すためにラズパイから取り出したMicroSDをMacにつないで初期化する。
以下のコマンドで初期化
$ diskutil eraseDisk FAT32 RPI /dev/disk2 Started erase on disk2 Unmounting disk Creating the partition map Waiting for partitions to activate Formatting disk2s2 as MS-DOS (FAT32) with name RPI 512 bytes per physical sector /dev/rdisk2s2: 60996480 sectors in 1906140 FAT32 clusters (16384 bytes/cluster) bps=512 spc=32 res=32 nft=2 mid=0xf8 spt=32 hds=255 hid=411648 drv=0x80 bsec=61026304 bspf=14892 rdcl=2 infs=1 bkbs=6 Mounting disk Finished erase on disk2
初期化前と初期化後で比較してみる
# 初期化前 $ diskutil list /dev/disk0 (internal): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme 500.3 GB disk0 1: EFI EFI 314.6 MB disk0s1 2: Apple_CoreStorage Macintosh HD 499.3 GB disk0s2 3: Apple_Boot Recovery HD 650.0 MB disk0s3 /dev/disk1 (internal, virtual): #: TYPE NAME SIZE IDENTIFIER 0: Apple_HFS Macintosh HD +499.0 GB disk1 Logical Volume on disk0s2 EF1D93DE-2460-4A71-B9DD-9C2223020689 Unlocked Encrypted /dev/disk2 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *31.5 GB disk2 1: DOS_FAT_32 NO NAME 700.4 MB disk2s1 2: Linux_Swap 511.7 MB disk2s2 3: Linux 30.2 GB disk2s3 #初期化後 $ diskutil list /dev/disk0 (internal): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme 500.3 GB disk0 1: EFI EFI 314.6 MB disk0s1 2: Apple_CoreStorage Macintosh HD 499.3 GB disk0s2 3: Apple_Boot Recovery HD 650.0 MB disk0s3 /dev/disk1 (internal, virtual): #: TYPE NAME SIZE IDENTIFIER 0: Apple_HFS Macintosh HD +499.0 GB disk1 Logical Volume on disk0s2 EF1D93DE-2460-4A71-B9DD-9C2223020689 Unlocked Encrypted /dev/disk2 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme *31.5 GB disk2 1: EFI EFI 209.7 MB disk2s1 2: Microsoft Basic Data RPI 31.2 GB disk2s2
ネットワークトラブル
無線親機を実家のネットワークに接続しようとしたら、「接続がタイムアウトしました」と出る。
使っている無線親機はBUFFEROのWMR-433W。調べるとファームウェアをアップデートするといいとのこと。参考
最新版のv1.5.2にアップデートしたものの結果は変わらず。
最終的には同じ機種を使っていた記事を見つけることができた。この記事を書いている間は実家に帰省していたこともあり、その場しのぎができればそれでよかった。そのため、この記事に習って実家にいるうちは有線でスイッチングハブとネットを接続することで解決することにした。
参考にしたサイト
- MacでRaspberryPi入門
- 3日間クッキング【Kubernetes のラズペリーパイ包み “サイバーエージェント風”】
- kubernetesのラズパイ包みが美味しそうだったので、kubeadmを使って作ってみた
- Raspberry Pi で動く様々なOS一覧まとめ13種類!
- RaspberryPi3でCentOS7を使う。
- MAC OS上でのオペレーティングシステムイメージのインストール
- Using CentOS 7.2.1511 Minimal on the Raspberry PI 3
- Docker comes to Raspberry Pi
- Raspberry Pi 3B系の 64bitモードに対応している OSの一覧まとめ 2018年版
- MacでSDカードをフォーマット(初期化)する方法【El Capitan 対応版】
ラズパイでKubernetesクラスタを構築する(物理編)
ラズベリーパイを触ったことがないので、後で見返すメモとして記録する。
この記事はラズパイケースにラズパイを設置する物理編である。
OSのインストールおよびKubernetesのインストールはラズパイクラスタにKubernetesのインストール(失敗編)とラズパイクラスタにKubernetesのインストール(成功編)の二つの記事に別途まとめる予定。
もともとこの記事を分割する予定はなかったものの、OSの選定が理由で作業が詰んでしまい大きく手戻りをすることになった。
その失敗をなかったことにするのはもったいないので、問題がなかった物理的な配線とOSインストール以降の失敗編と成功編の3つの記事に分けることにした。
用意したもの
年末に帰省したときに作業したので、実家にあるものはそのまま流用した。
ノートPCは除外するとして、最初から揃えるとするとだいたい3万円くらい?
必要なもの | 用途 |
---|---|
Raspberry Pi 3 Model B+ × 3 | これがなくちゃ始まらない |
4段積層式のラズパイケース | ラズパイを縦に積み重ねるため。リンクのものはラズパイ用のヒートシンクが4セット入っているのでお得 |
MicroSD 32GB×3 | ラズパイのディスクとして使う |
USBキーボード | ラズパイを操作するため。実家にあるだろうと思ったらなかったのでAmazonで注文 |
USBマウス | ラズパイを操作するため。自宅のを借用 |
USB Type-C ハブ | SDカードをMacBookProに認識させるため。自宅にも実家にもなかったのでAmazonで注文 |
USB充電器 | ラズパイの電源 |
スイッチングハブ | クラスタのSW |
LANケーブル(15cm×1本, 30cm×3本) | ラズパイ同士を接続するため |
ラズパイ用のディスプレイ | 実家のディスプレイを借用 |
HDMIケーブル | ラズパイをディスプレイに接続するため。実家のPS4のケーブルを拝借 |
Micro USBケーブル 30cm×3本 | ラズパイとUSB充電器を接続するため |
無線親機 | 無線LANにつなぐため |
両面テープ | USB充電器などをケースに固定するため |
全体の作業概要
- 物理的な配線(本記事の範囲)
- ラズパイにOSをインストール(ラズパイクラスタにKubernetesのインストール(失敗編/成功編))
- Kubernetesのインストール(ラズパイクラスタにKubernetesのインストール(成功編))
- Dockerをインストール
- Kubernetesのインストール
作り方
まずはケースを開封するとケース本体と工具箱が出てくる。工具箱にはドライバ、ピンセット、ヒートシンクなど必要なものが揃っている。このピンセットはヒートシンクの取り付けやナットを締めるのに便利だった。
まず、工具箱に入っているヒートシンクをラズパイの表に二箇所、裏に一箇所つける。
つぎに、ケースのアクリル板についている保護シートをはずす。保護シートとアクリル板の間には隙間がほとんどなく、剥がすのに苦労する。そんな時はアクリル板の四隅にあるネジ穴の内側から外側に向かって工具箱のドライバで強めに引っ掻いてやると、保護シートがめくれ上がって剥がしやすくなる。ここがドライバの唯一の出番だった。
保護シートを外したら説明書に従ってラズパイを取り付けていく。先ほど書いたように、ナットは付属のピンセットを使ったり爪で締めた。
4段目にはUSB充電器を設置する。両面テープを使って固定する。
最後に天板を取り付ける。ラズベリーがおしゃれ。
ただし、すぐに天板の上にスイッチハブと無線親機を乗せることになるのこのラズベリーとはお別れである。
スイッチハブと無線親機を15cmのLANケーブルで接続する。
ラズパイ本体にもLANを挿してスイッチングハブと接続する。
こうして全ての配線が済んだ。 本当はUSB充電器と同じようにスイッチングハブと無線親機も両面テープで固定したいが、年明けに実家から帰宅する途中に剥がれてしまいそうなので帰宅するまで我慢する。
あとはUSB充電器とスイッチングハブを電源に接続して完了。
物理的な配線を終えたので、本来であれば無線親機を設定する。
しかし、手元のWMR-433WがPPPoEに対応していなかったため実家の環境では無線の設定ができないことが分かったため、スイッチングハブを有線で接続した。 参考
参考にしたサイト
Golangでのつまずき その2
実践Go言語の説明を読んで実際にコードに書いて動作を確認したときにつまづいたポイントをまとめた。
埋め込みの動作確認でコンパイルエラー
また、埋込みを使うことで少し扱いやすくもなります。下の例では、通常の名前付きフィールドと並んで、埋込みフィールドを記述しています。
type Job struct { Command string *log.Logger }
これでJob型は、*log.Logger型が持つLog、Logfといったメソッドを持つようになりました。もちろん、Loggerにフィールド名を与えることはできますが、それは必須ではありません。これで一度初期化すればJobのログが記録できるようになります。
job.Log("starting now...")
この動作確認のため、以下のようなコードを書いた。
package main import "log" type Job struct { Command string *log.Logger } func main() { job := new(Job) job.Command = "aaa" job.Log("hoge") }
コンパイル結果はjob.Log undefined (type *Job has no field or method Log)
になった。
少なくとも、log
の中でLog
関数が定義されているらしき場所は見つからなかった。
説明の中で触れているlog
が組み込みのlog
ではなかったのか、手元のGoのバージョンでlog
の振る舞いが変わったのか。
Golangでのつまずき
Go言語を覚えるために試してひっかかったポイントをまとめた。
Goのバージョンはgo version go1.10.3 darwin/amd64
:=
を使った暗黙の変数定義を使えるのは関数の中だけ- aの定義をmain関数の中でするか,aの宣言にvarを使えばいい
:=
のスコープが関数の中にしかないのはGoの仕様
package main package main import "fmt" a:=5 func main() { if a > 2 { fmt.Println("a > 2") } else { fmt.Println("a <= 2") } } //コンパイル結果: ./main.go:5:1: syntax error: non-declaration statement outside function body
同じパッケージにある別のファイルで定義した関数の呼び出しでエラー
app2.go
package main // Compare compares byte arrays. func Compare(a, b []byte) int { for i := 0; i < len(a) && i < len(b); i++ { switch { case a[i] > b[i]: return 1 case a[i] > b[i]: return -1 } } switch { case len(a) < len(b): return -1 case len(a) > len(b): return 1 } return 0 } // Hoge is snipet for Compare function func Hoge() int { b1 := []byte{1, 2, 3} b2 := []byte{1, 2, 3} return Compare(b1, b2) }
- app1.go(トップレベルのファイル)
package main import ( "fmt" ) func main() { a := Hoge() fmt.Print(a) } // 実行結果: ./app1.go:8:7: undefined: Hoge
マップのエントリを削除するには、並列代入をひっくり返して、追加の論理値を右に書きます。論理値がfalseならエントリは削除されます。キーが既にマップから削除済みであっても安全に行う事ができます。 timeZone["PDT"] = 0, false; // Now on Standard Time
- 書いたコード
package main import ( "fmt" ) var timeZone = map[string]int{ "UTC": 0 * 60 * 60, "EST": -5 * 60 * 60, "CST": -6 * 60 * 60, "MST": -7 * 60 * 60, "PST": -8 * 60 * 60, } var tz string var seconds int var ok bool func main() { tz = "EST" timeZone[tz] = 10, false fmt.Println(timeZone[tz]) } // assignment mismatch: 1 variables but 2 values