/var/log/study

つまり雑記

VMware Photon OS で構築するK8Sクラスタ

Photon OS とは ?

github.com

VMware さんが作っているOSSで、コンテナをホストするためのOSです。

特徴は以下

  • おそらくRedHatベースのOS
  • tdnf (tiny dnf) という独自のパッケージ管理ツールが用いられている
  • systemd
  • network周りはsystemd-networkd

モダンなLinuxの普通構成? なのかな。

K8Sクラスタを作る方針

自分自身は過去にkubeadmでしかクラスタを作ったことが無いので、kubeadmで作りたいと思います。

kubernetes.io

で、kubeadmがサポートしているOSの中に、 Photon OS なんて無いので、 パッケージ管理ツールが絡んできそうな場所は Container Linux, それ以外のところは CentOS などを利用していくつもりです。

注意点

  • 今回はクラスタリングしたいVMがReady状態になるまでしか試していません
  • なので、クラスタが正常に動かない可能性が大いにあります
  • 個人的な不安点は、特にiptablesのルール周りです。

Photon OSの準備

github.com

上のwikiovaを使って、vSphereにデプロイ。

その後にやったことは以下

  • 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

github.com

また、PhotonOSのデフォルト状態だと、k8sAPIを叩くのに必要な6443ポートへの通信をDROPし、後の kubeadm join がfailedするのでポートを開けておく

iptables -I INPUT -p tcp --dport 6443 -m state --state NEW -j ACCEPT

一旦は検証なので、上記の感じで適当に開けるが、必要があればもう少し賢いルールを設定して、以下のissueを参考に永続化すると良い

github.com

kubeadmのインストール

基本的には以下の手順通りすすめる

kubernetes.io

上記の 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を複数台用意すること

あとは、以下に沿ってインストールを進めるだけ。

kubernetes.io

[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クラスタを作ることができました。

後日確認したいこと

kubernetes.io

上記のページに、 Check required ports があるので、そのポートが空いているか否かを確認しつつ、正常にクラスタが動いているか?を確認する必要がありそうです。

Hashicorp Nomad で タスクにクライアント側の変数を利用する

Nomad とは

Nomad というのはおしゃれな緑色のHashicorpプロダクト

www.nomadproject.io

同じく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")

ざっくりとした図は以下です。

f:id:yaaamaaaguuu:20180624120632p:plain

実現する方法

まず、クライアント側のサーバーを動かす設定ファイルの定義に 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

気づくのに時間がかかったので、覚書として。

全部ではないが、コードは以下

[Nomad] Use client side variables. · GitHub

pecoがxterm-256colorの際に文字化けるときの対処

ふとしたことがきっかけで、xterm-256colorのときにpecoが文字化けるようになってしまった。

github.com

自分と同じ症状が↑にまさしく出ていて、pecoの問題ではなく、pecoが利用しているtermbox-goとncursesとの問題とのことらしい。

自分の環境の $TERM あたりを中心に疑って見たが、pecoとncursesをアップデートしたらあっさりと治った。

Dockerを利用してgitlab pagesを試す

ためのdocker-compose.ymlを書いた。

このdocker-composeを動かすのに必要なのは以下

  • VM
    1. 4GB以上のメモリが搭載されたVM
    2. docker
    3. docker-compose
    4. gitlab-runner
  • DNS
    1. VMのIPに対してgitlab用のDNSレコードが設定されていること
    2. VMのIPに対してgitlab pages 用にワイルドカードなレコードが登録されていること

自宅のプライベートなネットワークでの利用の都合上、SSLの設定は切っている。

このymlで大事なのは13行目の gitlab_pages['inplace_chroot'] = true でコンテナ内でのpagesの利用を可能にしていること。

参考にしたissueは以下。

gitlab.com

以下がそのdocker-compose.yml

gist.github.com

systemd環境でDNSの向き先が変わらなかった

2018年の6月9日時点での話です。

Ubuntu18.04でいくら設定を変更しようとしてもDNSの向き先が変わらず若干悩みました。

結論から書くと、/etc/resolve.conf/run/systemd/resolve/resolv.confシンボリックリンクになっていることが期待されているのですが、シンボリックリンクになっていなかっただけです。

以下のリンクの質問と回答がドンピシャでした。

askubuntu.com

ubuntu 18.04 ではnetplanが導入されたので、その設定を変更しても、systemd-networkdの設定をいじっても、頑なに /etc/resolve.conf のnameserver は 127.0.0.53 を向いていたので何事だろうな?と思ったらsystemdのバグとのことでした。

Gitlab Development Kit のテストを回せるようにするための覚書

gitlab.com

↑ に沿えば良いのだけど、多分gitlab development kit (以下gdk) は普段の開発用ラップトップに導入される事をある程度前提としていると思う。

なので、クラウド上に作ったまっさらでしょぼいUbuntuとかにインストールしてもさくっとは動作しないので、セットアップ前後のフォローをこの記事でしたい。

この記事は2018年3月26日に書いている事に注意して頂きたい。

マシンスペック

gitlab自体を動かすrequirementsは以下に書いてある。

docs.gitlab.com

が、あまりにもしょぼいサーバーで bundle exec spec とかやり始めると、色々不都合が多い。

自分が用意した環境は以下

  • マシン
    • VMwareのESXi上に構築
    • ディスクはNFSのHDD
  • OS
  • CPU
    • 4vCPU
    • テストを回している最中のtopやvmstatを見ると、2vCPUでも大丈夫かなぁ?と言う気持ち
  • Memory
    • 16GB
    • swapが出ないように16GBにしたが、もう少しだけ絞っても大丈夫そう
  • Disk
    • 64GB
    • 容量的にギリギリっぽい
    • IOは特に問題にならない模様

set-up-gdk の前にやっておく必要があること

  1. rbenvなどでrubyのランタイムを用意
    • この記事を書いている時点では version 2.3.6
    • rbenv global 2.3.6
    • gem install bundler
  2. nodenvなどでnode.jsのランタイムの用意
    • この記事を書いている時点では version 8.9.4
    • nodenv global 8.9.4
    • npm install -g yarn
  3. chromeのインストール
    • その時の最新で良いと思う
  4. seleniumのchromedriverをインストール
  5. 必要なpostgresqlのバージョンをインストール
    • pg_config コマンドで表示されるバージョンがgitlabの利用するpostgresqlのバージョンとなる
    • pg_configpostgresql-server-dev というパッケージが提供するコマンド
    • postgresqlpostgresql-server-dev でバージョンがずれていないか意識する必要がある

テストを実行するには

  • gitlab-development-kit 配下で
    • gdk run
  • 別端末なりtmuxでの分割なりで
    • seleniumのchromedriverを動かす
      • chromedriver
  • 別端末なりtmuxでの分割なりで
    • gitlab-development-kit/gitlab 配下で
      • selenium周りで問題が無いかチェックする
        • bundle exec rspec spec/features/merge_requests/filters_generic_behavior_spec.rb
      • rspecのテストを回す
        • bundle exec spec

既存のvSphere環境をTerraform import して管理する

yaaamaaaguuu.hatenablog.com

ほぼ1年越しの再入門。既存のvSphere環境を管理するために色々と試してみる

今回は, フォルダとvDS, データストアをインポートして ~planで差分がなくなるところ~ だるかったのでインポートまで。

terraform v0.11.3 で検証

色々試す前の確認事項

ワークフロー

  • 初回のみ
    • terraform init
  • 以降
    1. tf ファイルに既存の構成を書く
    2. terraform import で既存の構成をインポート
    3. terraform plan で確認
  • 変更があれば
    1. tf ファイルを編集
    2. terraform plan で確認
    3. terraform apply で実行

importなりapplyなりをすると、terraform.tfstateが作成される。tfstateに無いものは新規作成としてみなされるっぽい。

でもって、terraform.tfstateをgitで管理する?とかは以下に書いてあるので、適当なタイミングで調査しようと思う。

www.terraform.io

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のフォルダ

現状は以下の感じ。

f:id:yaaamaaaguuu:20180311155302p:plain

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.

ネットワーク

既存のネットワークは以下

f:id:yaaamaaaguuu:20180311173226p:plain

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こめのnicvusb0 になっているはIntelのNUCにusb nicをくっつけているから。

yaaamaaaguuu.hatenablog.com

$ 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

すると結構差分が出るので、後はドキュメントを読んで差分を埋める

ストレージ

f:id:yaaamaaaguuu:20180311175223p:plain

現状は上記

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

こんな感じになった。