VMware Photon OS で構築するK8Sクラスタ
Photon OS とは ?
VMware さんが作っているOSSで、コンテナをホストするためのOSです。
特徴は以下
- おそらくRedHatベースのOS
- tdnf (tiny dnf) という独自のパッケージ管理ツールが用いられている
- systemd
- network周りはsystemd-networkd
モダンなLinuxの普通構成? なのかな。
K8Sクラスタを作る方針
自分自身は過去にkubeadmでしかクラスタを作ったことが無いので、kubeadmで作りたいと思います。
で、kubeadmがサポートしているOSの中に、 Photon OS
なんて無いので、 パッケージ管理ツールが絡んできそうな場所は Container Linux
, それ以外のところは CentOS
などを利用していくつもりです。
注意点
Photon OSの準備
その後にやったことは以下
hostnamectl set-hostname name
で適当にhostnameを変更- 100GBのディスクを
/var/lib/docker
に追加 - echo 'export PATH="${PATH}:/opt/bin"' >> ~/.bash_profile
tdnf install -y tar wget ebtables ethtool socat
K8S向けの特別な対応
何もせずに、kubeadmでセッティングしていくと、 kube-dns
というやつがクラッシュして再起動しまくるので、issueを参考に設定を入れる
cat << EOF > /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=cgroupfs"] } EOF
また、PhotonOSのデフォルト状態だと、k8sのAPIを叩くのに必要な6443ポートへの通信をDROPし、後の kubeadm join
がfailedするのでポートを開けておく
iptables -I INPUT -p tcp --dport 6443 -m state --state NEW -j ACCEPT
一旦は検証なので、上記の感じで適当に開けるが、必要があればもう少し賢いルールを設定して、以下のissueを参考に永続化すると良い
kubeadmのインストール
基本的には以下の手順通りすすめる
上記の Installing kubeadm, kubelet and kubectl
の項目は Container Linux
の全部と CentOS
の以下のコマンドを実行した
cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
kubernetes のインストール
ここまでの状態のPhotonOSのVMを複数台用意すること
あとは、以下に沿ってインストールを進めるだけ。
[WARNING FileExisting-crictl]: crictl not found in system path
というWARNINGが出るが、 2018/06/24 時点では、crictlをインストールするとk8sのインストール段階でエラーになって結局ignore-errorするハメになるので無視で良さそう
自分は3VM用意して kubectl get nodes
の結果は以下のような状態になった。
root@k8s-photon-001-v [ ~ ]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-photon-001-v Ready master 34m v1.10.5 k8s-photon-002-v Ready <none> 31m v1.10.5 k8s-photon-003-v Ready <none> 31m v1.10.5
検証中はちょいちょいハマりどころはあったものの、特に問題なくPhotonOSとkubeadmでK8Sクラスタを作ることができました。
後日確認したいこと
上記のページに、 Check required ports
があるので、そのポートが空いているか否かを確認しつつ、正常にクラスタが動いているか?を確認する必要がありそうです。
Hashicorp Nomad で タスクにクライアント側の変数を利用する
Nomad とは
Nomad というのはおしゃれな緑色のHashicorpプロダクト
同じくHashicorpのConsulというツールと連動してジョブのスケジューラーとして動作してくれる製品です。
アーキテクチャ
NomadにはServerというユーザーからジョブを受け付けるヤツと、Clientというジョブを実際に実行するヤツとがいるっぽいです。
あまりきちんとドキュメントを読み込んでいないので、正しくないかもしれないですが。
実現したいしたいこと
あるジョブを実行した際、ホストごとに設定される環境変数を読み取り、挙動を変えたいと思いました。
以下のようなコードの中の DOMAIN
をクライアントごとに切り替えたいという話です。
from flask import Flask import os app = Flask(__name__) @app.route("/", methods=["GET"]) def root(): return os.getenv("DOMAIN", "None") if __name__ == "__main__": app.run(host="0.0.0.0")
ざっくりとした図は以下です。
実現する方法
まず、クライアント側のサーバーを動かす設定ファイルの定義に meta
というセクションを指定し、その中で適当に変数を宣言します
client { enabled = true servers = [ "ipaddress" ] meta { domain="This is domain value." } }
次に、ジョブの定義の中で、クライアントのmetaを拾えるようにします。
以下の設定の中の、 envというところで、 DOMAIN="${meta.domain}"
を指定しています。
こうすることで、上で示した実行したいコードは DOMAIN
という環境変数がセットされた上で実行されるようになります。
job "web-app"{ datacenters = ["dc1"] type = "system" update { stagger = "10s" max_parallel = 1 } task "webservice" { driver = "docker" config { image = "flask-app:1.2.0" port_map { web = 5000 } } resources { network { port "web" {} } } env { DOMAIN = "${meta.domain}" } } }
以下の話は、ドキュメント に以下のように記載されていました。
${meta.key} | Metadata value given by key on the client | ${meta.foo} => bar
気づくのに時間がかかったので、覚書として。
全部ではないが、コードは以下
pecoがxterm-256colorの際に文字化けるときの対処
ふとしたことがきっかけで、xterm-256colorのときにpecoが文字化けるようになってしまった。
自分と同じ症状が↑にまさしく出ていて、pecoの問題ではなく、pecoが利用しているtermbox-goとncursesとの問題とのことらしい。
自分の環境の $TERM
あたりを中心に疑って見たが、pecoとncursesをアップデートしたらあっさりと治った。
Dockerを利用してgitlab pagesを試す
systemd環境でDNSの向き先が変わらなかった
2018年の6月9日時点での話です。
Ubuntu18.04でいくら設定を変更しようとしてもDNSの向き先が変わらず若干悩みました。
結論から書くと、/etc/resolve.conf
は /run/systemd/resolve/resolv.conf
のシンボリックリンクになっていることが期待されているのですが、シンボリックリンクになっていなかっただけです。
以下のリンクの質問と回答がドンピシャでした。
ubuntu 18.04 ではnetplanが導入されたので、その設定を変更しても、systemd-networkdの設定をいじっても、頑なに /etc/resolve.conf
のnameserver は 127.0.0.53
を向いていたので何事だろうな?と思ったらsystemdのバグとのことでした。
Gitlab Development Kit のテストを回せるようにするための覚書
↑ に沿えば良いのだけど、多分gitlab development kit (以下gdk) は普段の開発用ラップトップに導入される事をある程度前提としていると思う。
なので、クラウド上に作ったまっさらでしょぼいUbuntuとかにインストールしてもさくっとは動作しないので、セットアップ前後のフォローをこの記事でしたい。
この記事は2018年3月26日に書いている事に注意して頂きたい。
マシンスペック
gitlab自体を動かすrequirementsは以下に書いてある。
が、あまりにもしょぼいサーバーで bundle exec spec
とかやり始めると、色々不都合が多い。
自分が用意した環境は以下
- マシン
- OS
- CPU
- 4vCPU
- テストを回している最中のtopやvmstatを見ると、2vCPUでも大丈夫かなぁ?と言う気持ち
- Memory
- 16GB
- swapが出ないように16GBにしたが、もう少しだけ絞っても大丈夫そう
- Disk
- 64GB
- 容量的にギリギリっぽい
- IOは特に問題にならない模様
set-up-gdk の前にやっておく必要があること
- rbenvなどでrubyのランタイムを用意
- この記事を書いている時点では version
2.3.6
rbenv global 2.3.6
gem install bundler
- この記事を書いている時点では version
- nodenvなどでnode.jsのランタイムの用意
- この記事を書いている時点では version
8.9.4
nodenv global 8.9.4
npm install -g yarn
- この記事を書いている時点では version
- chromeのインストール
- その時の最新で良いと思う
- seleniumのchromedriverをインストール
- その時の最新で良いと思う
- https://chromedriver.storage.googleapis.com/index.html で確認できる
- 一番下にあるのは最新ではなく、数字が大きいやつが最新
- 必要なpostgresqlのバージョンをインストール
pg_config
コマンドで表示されるバージョンがgitlabの利用するpostgresqlのバージョンとなるpg_config
はpostgresql-server-dev
というパッケージが提供するコマンドpostgresql
とpostgresql-server-dev
でバージョンがずれていないか意識する必要がある
テストを実行するには
既存のvSphere環境をTerraform import して管理する
ほぼ1年越しの再入門。既存のvSphere環境を管理するために色々と試してみる
今回は, フォルダとvDS, データストアをインポートして ~planで差分がなくなるところ~ だるかったのでインポートまで。
terraform v0.11.3 で検証
色々試す前の確認事項
ワークフロー
- 初回のみ
terraform init
- 以降
-
tf
ファイルに既存の構成を書く -
terraform import
で既存の構成をインポート -
terraform plan
で確認
-
- 変更があれば
-
tf
ファイルを編集 -
terraform plan
で確認 -
terraform apply
で実行
-
importなりapplyなりをすると、terraform.tfstateが作成される。tfstateに無いものは新規作成としてみなされるっぽい。
でもって、terraform.tfstateをgitで管理する?とかは以下に書いてあるので、適当なタイミングで調査しようと思う。
tfファイルの構成
terraformはカレントディレクトリにある tf
ファイルを全て読み込んで実行するとの事。
なので一旦はansibleのようにディレクトリ構成は考えずに取り組んでいく
tf内の用語
- providor
- 接続情報とか
- data
- たぶん参照系
- resource
- たぶん自分で作りたいやつ
- variable
- 変数
まず接続確認
providor.tf
を作り接続確認
variable "vsphere_user" { default = "administrator@vsphere.local" # デフォルトを入れておくと、コマンド実行時に引数を与えなくて済む } variable "vsphere_password" { # なにも定義せずに実行すると該当の変数に何を入れるか実行時に聴いてくれる # もちろんコマンドラインの引数で与えてもOK # ただしterraform import のときはコマンドライン引数に与えてあげる必要がある } variable "vsphere_server" { } provider "vsphere" { user = "${var.vsphere_user}" password = "${var.vsphere_password}" vsphere_server = "${var.vsphere_server}" # if you have a self-signed cert allow_unverified_ssl = true }
こんな感じのファイルを作った後に、vSphere providoerをインストールするために以下のコマンドを叩く
$ terraform init Initializing provider plugins... - Checking for available provider plugins on https://releases.hashicorp.com... - Downloading plugin for provider "vsphere" (1.3.3)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.vsphere: version = "~> 1.3" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
するとversionの出力にvsphereのprovidorが追加される
$ terraform --version Terraform v0.11.3 + provider.vsphere v1.3.3
そしたら接続確認の為に terraform plan
を実行する
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
データセンターを確認する
vsphere_datacenter
がデータとリソースで使える
確認するつもりだったが、datacenterはimportに未対応なのでdataで参照系だけ定義しておく
datacenter.tf
で。
data "vsphere_datacenter" "my_dc" { name = "mycloud" }
$ tree . ├── datacenter.tf ├── providor.tf
VMのフォルダ
現状は以下の感じ。
administration を管理するようにする
インポートする前に既存の定義を書く
administration.tf
とする
resource "vsphere_folder" "administration" { path = "administration" type = "vm" datacenter_id = "${data.vsphere_datacenter.my_dc.id}" }
$ tree . ├── administration.tf ├── datacenter.tf ├── providor.tf
インポートする
https://www.terraform.io/docs/providers/vsphere/r/folder.html#importing
上記を参考に
$ terraform import -var="vsphere_password=####" vsphere_folder.administration /mycloud/vm/administration vsphere_folder.administration: Importing from ID "/mycloud/vm/administration"... vsphere_folder.administration: Import complete! Imported vsphere_folder (ID: group-v687) vsphere_folder.administration: Refreshing state... (ID: group-v687) Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
確認する
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. data.vsphere_datacenter.my_dc: Refreshing state... vsphere_folder.administration: Refreshing state... (ID: group-v687) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
ネットワーク
既存のネットワークは以下
myprivate
を管理出来るようにする
インポートする前に定義を書く
まずESXiのデータ定義を書く必要があるので、 hosts.tf
で以下を書く
variable "esxi_hosts" { default = [ "esxi1.mycloud.local", "esxi2.mycloud.local", "esxi3.mycloud.local", ] } variable "network_interfaces" { default = [ "vmnic0", "vusb0" ] } data "vsphere_host" "host" { count = "${length(var.esxi_hosts)}" name = "${var.esxi_hosts[count.index]}" datacenter_id = "${data.vsphere_datacenter.my_dc.id}" }
2こめのnicが vusb0
になっているはIntelのNUCにusb nicをくっつけているから。
$ tree . ├── administration.tf ├── datacenter.tf ├── hosts.tf ├── providor.tf
次にネットワークのリソースを書く
network.tf
resource "vsphere_distributed_virtual_switch" "myprivate_dvs" { name = "myprivate" datacenter_id = "${data.vsphere_datacenter.my_dc.id}" uplinks = ["uplink1"] active_uplinks = ["uplink1"] host { host_system_id = "${data.vsphere_host.host.0.id}" devices = ["${var.network_interfaces}"] } host { host_system_id = "${data.vsphere_host.host.1.id}" devices = ["${var.network_interfaces}"] } host { host_system_id = "${data.vsphere_host.host.2.id}" devices = ["${var.network_interfaces}"] } }
インポートする
$ terraform import --var="vsphere_password=####" vsphere_distributed_virtual_switch.myprivate_dvs /mycloud/network/myprivate vsphere_distributed_virtual_switch.myprivate_dvs: Importing from ID "/mycloud/network/myprivate"... vsphere_distributed_virtual_switch.myprivate_dvs: Import complete! Imported vsphere_distributed_virtual_switch (ID: 50 2d 17 35 c3 ea f4 f3-32 64 07 3c 8e 3a d8 8a) vsphere_distributed_virtual_switch.myprivate_dvs: Refreshing state... (ID: 50 2d 17 35 c3 ea f4 f3-32 64 07 3c 8e 3a d8 8a) Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
plan
terraform plan
すると結構差分が出るので、後はドキュメントを読んで差分を埋める
ストレージ
現状は上記
import前の定義
storage.tfで以下のように書く
resource "vsphere_nas_datastore" "storage1" { name = "storage1.mycloud.local" host_system_ids = ["${data.vsphere_host.host.*.id}"] type = "NFS" remote_hosts = ["storage1.mycloud.local"] remote_path = "/data/virtual-machines" }
import
データストアのインポートにはmoidが必要らしいのでweb clientのurlから適当に拾ってくる
$ terraform import -var="vsphere_password=###" vsphere_nas_datastore.storage1 datastore-11 vsphere_nas_datastore.storage1: Importing from ID "datastore-11"... vsphere_nas_datastore.storage1: Import complete! Imported vsphere_nas_datastore (ID: datastore-11) vsphere_nas_datastore.storage1: Refreshing state... (ID: datastore-11) Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
plan
terraform plan
ストレージのpalnは特に差分が出ない
一旦まとめ
$ tree . ├── administration.tf ├── datacenter.tf ├── hosts.tf ├── network.tf ├── providor.tf ├── storage.tf ├── terraform.tfstate └── terraform.tfstate.backup
こんな感じになった。