Ubuntu 18.04でJava開発環境を整える

Ubuntu 18.04日本語版をインストールしてJava開発環境を構築するときのメモ書き。随時更新予定。

フォルダ名を英語にする。

日本語環境にすると、ホームにあるフォルダ名が日本語になる。コマンドラインで使うときに不便なので英語の名前に変換する。

LANG=C xdg-user-dirs-gtk-update

日本語入力切替キーを変更する

日本語入力の切り替えをMacと同じにする。会社ではMacを使っているので、甚だ不便。 以下の説明は、Mozcを使用している場合。

  1. アプリケーションの一覧より、Mozcを検索して、Mozcの設定画面を起動。
  2. 一般タブにあるキー設定 - キー設定の選択 - 編集ボタンをクリック。
  3. モードが変換前入力中、入力キーがMuhenkanを探す。この行のコマンド列の設定を、IMEを無効化に変更。
  4. 同様に、モードが変換中、入力キーがMuhenkanを探す。この行のコマンド列の設定を、IMEを無効化に変更。
  5. 同様に、モードが文字入力無し、入力キーがMuhenkanを探す。この行のコマンド列の設定を、IMEを無効化に変更。
  6. モードが文字入力無し、入力キーがHenkanを探す。この行のコマンド列の設定を、IMEを有効化に変更。

ついでにCtrlキーも入れ替えるかどうか悩みどころ。

KeePassXC

パスワードマネージャのKeePassXCをインストール。私はこれがないとパスワードが分からん。

sudo apt install keepassxc

Visual Studio Code

テキストエディタVisual Studio Codeをインストール。このサイト(https://code.visualstudio.com/)からダウロードしてファイルマネジャーで実行。

Guakeをインストール

ターミナルソフトである、Guake Terminalをインストール。標準の端末と比べて、常駐してショートカットキーでさっと起動できるので、こちらのほうが便利。 ログオン時に自動起動すると便利なので、Tweek Toolをインストールして設定する。

sudo apt install guake

terminatorというターミナルも気になっているので、今度使ってみることにしよう。

Tweak Tool

Gnome Destopをカスタマイズできるtweek-toolをインストール。

sudo apt install gnome-tweak-tool

このツールで以下の設定を行う。

  • guakeをログオン時に自動起動する。スタートアップアプリケーションタブで設定。

SDKMan

開発ツールのパッケージマネージャである、SDK Manをインストール。Javaやgradleはこれを使ってインストールすることにする。

sudo apt install curl
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

インストールの確認

yaku@yaku-H97M-D3H:~$ sdk version
==== BROADCAST =================================================================
* 2019-02-21: Kscript 2.7.1 released on SDKMAN! #kscript
* 2019-02-19: Grails 4.0.0.M1 released on SDKMAN! #grailsfw
* 2019-02-16: Kscript 2.7.0 released on SDKMAN! #kscript
================================================================================

Javaのインストール

SDK Manを使用してJavaをインストールする。まずはインストール可能なバージョンを確認。

yaku@yaku-H97M-D3H:~$ sdk list java
================================================================================
Available Java Versions
================================================================================
     13.ea.07-open       8.0.202.j9-adpt                                        
     12.ea.31-open       8.0.202.hs-adpt                                        
     11.0.2-sapmchn      8.0.202-zulufx                                         
     11.0.2-zulu         8.0.201-oracle                                         
     11.0.2-open         7.0.211-zulu                                           
     11.0.2-amzn         6.0.119-zulu                                           
     11.0.2.j9-adpt      1.0.0-rc-12-grl                                        
     11.0.2.hs-adpt      1.0.0-rc-11-grl                                        
     11.0.2-zulufx       1.0.0-rc-10-grl                                        
     10.0.2-zulu         1.0.0-rc-9-grl                                         
     10.0.2-open         1.0.0-rc-8-grl                                         
     9.0.7-zulu                                                                 
     9.0.4-open                                                                 
     8.0.202-zulu                                                               
     8.0.202-amzn                                                               

================================================================================
+ - local version
* - installed
> - currently in use
================================================================================

OpenJSKバージョンである、11.0.2-openを使うことにする。

sdk install java 11.0.2-open

JAVA_HOMEを、.bashrcに設定する。以下の行を追加。

export JAVA_HOME=$HOME/.sdkman/candidates/java/current

Gradleのインストール

SDK Manを使用してインストールする。インストール可能なバージョンを確認。

yaku@yaku-H97M-D3H:~$ sdk list gradle
================================================================================
Available Gradle Versions
================================================================================
     5.2.1               4.3.1               2.14                1.10           
     5.2                 4.3                 2.13                1.9            
     5.1.1               4.2.1               2.12                1.8            
     5.1                 4.2                 2.11                1.7            
     5.0                 4.1                 2.10                1.6            
     4.10.3              4.0.2               2.9                 1.5            
     4.10.2              4.0.1               2.8                 1.4            
     4.10.1              4.0                 2.7                 1.3            
     4.10                3.5.1               2.6                 1.2            
     4.9                 3.5                 2.5                 1.1            
     4.8.1               3.4.1               2.4                 1.0            
     4.8                 3.4                 2.3                 0.9.2          
     4.7                 3.3                 2.2.1               0.9.1          
     4.6                 3.2.1               2.2                 0.9            
     4.5.1               3.2                 2.1                 0.8            
     4.5                 3.1                 2.0                 0.7            
     4.4.1               3.0                 1.12                               
     4.4                 2.14.1              1.11                               

================================================================================
+ - local version
* - installed
> - currently in use
================================================================================

最新版のインストール。

sdk install gradle

IntellJ IDEAをインストール

このサイト(https://www.jetbrains.com/idea/download/#section=linux)からダウンロードしてインストールする。

ダウンロード終了後、ファイルを展開

tar xzvf  ~/Downloads/ideaIC-2018.3.4.tar.gz

展開されたファイルを/usr/local/ideaに移動。

sudo mv idea-IC-183.5429.30/ /usr/local/idea

起動してセットアップ

/usr/local/idea/bin/idea.sh

Docker

Dockerのインストールは、この公式サイト(https://docs.docker.com/install/linux/docker-ce/ubuntu/)の説明どうりにやる。

Spotify

SpotifyはありがたいことにUbuntuで動作するPlayerを提供している。やっぱり音楽がないと始まらない。このページの説明を読めばインストールできる。

Ubuntu 18.04にTP-Link AC1900 11ac PCI-Expressのドライバを入れる

Ubuntu 18.04でTP-LinkのAC1900 11ac PCI-Expressが認識しませんでした。 このネットワークカードは、 Broadcom BCM4360 のチップらしく、Ubuntuでもサポートしているようなのですが、認識しないので以下のようにしてインストールしました。

sudo apt-get install --reinstall bcmwl-kernel-source
sudo modprobe wl

有線LAN環境がないとネットが使えず、apt-get installも出来ませんが、手持ちのiPhoneテザリングして繋いで解決しました。 いざというときのために、有線も使える環境にするべきかなー。

高可用性Kubernetes Clusterを構築する-その2

前回に引き継き、Kubernetes Cluster(v1.13)を構築していきます。

最初のControl Plane Nodeのセットアップ

kubeadmで初期設定

1台目のControl Plane Nodeをセットアップします。セットアップ用に以下の内容のkubeadm-config.ymlファイルを作成します。 設定は前回の記事の構成で説明したホストの環境になっています。 advertiseAddressは、ネットワークインターフェイスが複数ある場合に、使用したいインターフェイスを指定します。 podSubnetの指定は、CNIドライバ依存です。今回はkube-routerを使用します。

apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "192.168.33.22"
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: stable
apiServer:
  certSANs:
  - "host1"
controlPlaneEndpoint: "host1:6443"
networking:
  podSubnet: 10.244.0.0/16

次に、kubeadm initコマンドで初期化します。コマンド実行時の最後に、他のノードをJoinする設定(kubeadm join ...)が出力されます。この出力される内容は記録しておいてください。

sudo kubeadm init --config=kubeadm-config.yml

[init] Using Kubernetes version: v1.13.2
[preflight] Running pre-flight checks
[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 \"etcd/ca\" certificate and key
[certs] Generating \"etcd/healthcheck-client\" certificate and key
[certs] Generating \"apiserver-etcd-client\" certificate and key
[certs] Generating \"etcd/server\" certificate and key
[certs] etcd/server serving cert is signed for DNS names [host2 localhost] and IPs [192.168.33.22 127.0.0.1 ::1]
[certs] Generating \"etcd/peer\" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [host2 localhost] and IPs [192.168.33.22 127.0.0.1 ::1]
[certs] Generating \"ca\" certificate and key
[certs] Generating \"apiserver-kubelet-client\" certificate and key
[certs] Generating \"apiserver\" certificate and key
[certs] apiserver serving cert is signed for DNS names [host2 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local host1 host1] and IPs [10.96.0.1 192.168.33.22]
[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
[apiclient] All control plane components are healthy after 19.009590 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 \"host2\" as an annotation
[mark-control-plane] Marking the node host2 as control-plane by adding the label \"node-role.kubernetes.io/master=''\"
[mark-control-plane] Marking the node host2 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: t5nhqp.gmv92atuy5ckcs1l
[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 host1:6443 --token t5nhqp.gmv92atuy5ckcs1l --discovery-token-ca-cert-hash sha256:cb9ff5930d75ce0676d19f1ec14b93515d4f23e6294d60cba37da7a10348d164

終了したら、現在ログインしているアカウントでkubectlコマンドを使えるように初期設定します。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

CNI Pluginの設定

CNI Pluginの初期化を行います。今回は、kube-routerを使います。kube-routerの設定の詳細はこちらを参照してください。

kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter-all-features.yaml

Kube-systemを削除します。

kubectl -n kube-system delete ds kube-proxy
sudo docker run --privileged -v /lib/modules:/lib/modules --net=host k8s.gcr.io/kube-proxy-amd64:v1.10.2 kube-proxy --cleanup

初期化後Kubenetesのpodsを確認し、各Podが起動できているか確認します。 RADYとSTATUSの列を確認して、以下のようになっていれば起動しています。

kubectl get pod -n kube-system -w
NAME                            READY   STATUS    RESTARTS   AGE
coredns-86c58d9df4-fd8wh        1/1     Running   0          3m9s
coredns-86c58d9df4-s2mqx        1/1     Running   0          3m9s
etcd-host2                      1/1     Running   0          2m22s
kube-apiserver-host2            1/1     Running   0          2m5s
kube-controller-manager-host2   1/1     Running   0          2m9s
kube-router-9dmtt               1/1     Running   0          2m16s
kube-scheduler-host2            1/1     Running   0          2m31s

証明書ファイルを他のホストにコピー

以下のように、作成された証明書ファイルを他のControl Plane Nodeにコピーします。 証明書は権限がルートしか参照できないものもあるので、ルートユーザで行います。 ルートユーザから他のホストにUSER環境変数で指定しているユーザでログインできるようにしています。 この例は、suでrootになり、USER環境変数vagrantユーザを指定してscpでコピーしています。

sudo su
export USER=vagrant # customizable
CONTROL_PLANE_IPS="192.168.33.23 192.168.33.24"
for host in ${CONTROL_PLANE_IPS}; do
    scp /etc/kubernetes/pki/ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.key "${USER}"@$host:
    scp /etc/kubernetes/pki/sa.pub "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.crt "${USER}"@$host:
    scp /etc/kubernetes/pki/front-proxy-ca.key "${USER}"@$host:
    scp /etc/kubernetes/pki/etcd/ca.crt "${USER}"@$host:etcd-ca.crt
    scp /etc/kubernetes/pki/etcd/ca.key "${USER}"@$host:etcd-ca.key
    scp /etc/kubernetes/admin.conf "${USER}"@$host:
done

残りホストにログインして設定

残りのhost3, host4にログインし、先ほどコピーした証明書をインストールします。

sudo su
USER=vagrant # customizable
mkdir -p /etc/kubernetes/pki/etcd
mv /home/${USER}/ca.crt /etc/kubernetes/pki/
mv /home/${USER}/ca.key /etc/kubernetes/pki/
mv /home/${USER}/sa.pub /etc/kubernetes/pki/
mv /home/${USER}/sa.key /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.crt /etc/kubernetes/pki/
mv /home/${USER}/front-proxy-ca.key /etc/kubernetes/pki/
mv /home/${USER}/etcd-ca.crt /etc/kubernetes/pki/etcd/ca.crt
mv /home/${USER}/etcd-ca.key /etc/kubernetes/pki/etcd/ca.key
mv /home/${USER}/admin.conf /etc/kubernetes/admin.conf

クラスタに参加

最初のノード設定時にkubeadm initコマンド実行で表示されたjoinコマンドの表示を使用して、以下のようにrootユーザでhost3, host4で実行してクラスタに参加します。 クラスタ用のControl Plane Nodeの場合、--experimental-control-planeオプションをつけて実行します。 あと、--apiserver-advertise-addressオプションは、ネットワークカードが複数ある環境の場合に、接続するネットワークを指定するコマンドです。 ホスト毎にIPアドレスを自ホストの接続するアドレスに変えます。 今回、virtualbox環境で実行しているため、複数のネットワークカードがあります。このためオプションを指定しています。

sudo kubeadm config images pull
kubeadm join host1:6443\
 --token t5nhqp.gmv92atuy5ckcs1l\
 --discovery-token-ca-cert-hash sha256:cb9ff5930d75ce0676d19f1ec14b93515d4f23e6294d60cba37da7a10348d164\
 --experimental-control-plane\
 --apiserver-advertise-address=192.168.33.23

コマンド実行が終わったら、kubectlのコマンド設定を行って、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

同じ作業を、host4に実行します。終了すれば、Control plane nodeの構築は完了です。

MasterノードにもPodがスケジュールされるようにする

今回はサーバ台数が少ないので、Control Plane Nodeにpodがスケジュールリングされるようにします。

kubectl taint nodes --all node-role.kubernetes.io/master-

以上で終了です。

注:ちゃんとpodをデプロイして動くかどうかの十分な検証はこれからです・・。

参考

高可用性Kubernetes Clusterを構築する-その1

検証用に高可用性のKubernetes Clusterを、kubeadmの公式ガイドを参考にVagrant環境にインストールする方法をまとめました。

私が担当している某BGM配信サービスでKubernetesを使用していますが、最近のバージョンではなかなか上がらなかった推奨Dockerバージョンが上り、標準のDNSがCoreDNSに変更されていたりするので、バージョンアップした方が良い気がしてきました。ですが、マメにバージョンアップしていなかったせいで、バージョンアップが難しい状況になっています。そこで、一から構築する方法をとりました。 構築はkubeadmを使用します。このKubernetes Clusterの構築方法はkubeadmのバージョンアップと共に変わってきており、今回はv1.13で紹介されている方法で構築します。

構成

OSはUbuntu 18.04LTSを使用し、kubernetesはVersion 1.13、kube-apiserver用のロードバランサを1台、Control Plane Node兼ワーカー共用ホストを3台の全4台のサーバを準備します。 こちら(https://kubernetes.io/docs/setup/independent/ha-topology/)の説明にあるように本来Control Plane Nodeとワーカーを別ホストにする方が安定性は良いのですが、構築の検証用のため、この構成で構築したいと思います。 これらのサーバは、メモリの最低の推奨環境が2Gbなので、それぞれメモリを2Gbにしています。

ホスト名 IPアドレス 役割
host1 192.168.33.21 APIロードバランサー
host2 192.168.22.22 Kubernetes control plane node/worker1
host3 192.168.22.23 Kubernetes control plane node/worker2
host4 192.168.22.24 Kubernetes control plane node/worker3

構築用のVgrantファイル

構築用のVagrantファイルは以下のようにしました。一度に4台のサーバを立ち上げます。

# -*- mode: ruby -*-
# vi: set ft=ruby :

HOST_COUNT = 4
BOX_IMAGE = "ubuntu/bionic64"

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://atlas.hashicorp.com/search.
  config.vm.box = BOX_IMAGE

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  #config.vm.network "private_network", ip: "192.168.33.20"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
  # such as FTP and Heroku are also available. See the documentation at
  # https://docs.vagrantup.com/v2/push/atlas.html for more information.
  # config.push.define "atlas" do |push|
  #   push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
  # end
  #config.vm.synced_folder ".", "/vagrant_data"

  (1..HOST_COUNT).each do |i|
    config.vm.define "host#{i}" do |subconfig|
      subconfig.vm.box = BOX_IMAGE
      subconfig.vm.hostname = "host#{i}"
      subconfig.vm.network :private_network, ip: "192.168.33.#{i + 20}"

      subconfig.vm.provider "virtualbox" do |vb1|
        # Display the VirtualBox GUI when booting the machine
        # Customize the amount of memory on the VM:
        vb1.memory = "2048"
        vb1.customize ["modifyvm", :id, "--paravirtprovider", "kvm"]
      end
    end
  end
  
  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.  config.vm.provision "shell", inline: "sudo apt install -y python"

  config.vm.provision "shell", inline: <<-SHELL
    sudo apt-get update
    sudo apt-get install -y python python-simplejson language-pack-ja-base language-pack-ja
  SHELL
end

ロードバランサーの構築

kube-apiserver用のロードバランサーを構築します。ロードバランサのソフトウェアは、haproxyを使用します。

haproxyのセットアップ

apt install haproxy

haproxyの設定

haproxyの設定は、/etc/haproxy/haproxy.cnfに以下のように設定します。

global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # Default ciphers to use on SSL-enabled listening sockets.
    # For more information, see ciphers(1SSL). This list is from:
    #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
    # An alternative list with additional directives can be obtained from
    #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3

defaults
    log global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
         timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

frontend kubeapi
    bind *:6443
    mode tcp
    option tcplog
    default_backend kube_cp

backend kube_cp
    mode tcp
    option tcplog
    option tcp-check
    balance roundrobin
    server host2    192.168.33.22:6443 check port 6443
    server host3    192.168.33.23:6443 check port 6443
    server host4    192.168.33.24:6443 check port 6443

設定後、haproxyを再起動します。

sudo systemctl restart haproxy

前準備

クラスタを構成するホストに、docker、kubelet、kubeadminをインストールします。以下の設定は、全てのホストに対して実行します。

swapを無効にする

swapを無効にすることがKubenetes nodeサーバに対して必須構成なので、swapを無効にします。 vagrantで使用するboxによってはswapがない場合もあるので、この場合は設定しなくて大丈夫です。

sudo swapoff -a

vm.swappinessの設定を0にします。起動後も有効になるように、/etc/sysctl.confに以下の行を追加します。

vm.swappiness = 0

再読み込みします。

sudo sysctl -p

以下のコマンドでswap領域を確認できるので、このパーティションを/etc/fstabから削除します。 fstabのパーティションタイプがswap担っているので、この行を削除すると良いです。

cat /proc/swaps

Dockerのインストール

Dockerをインストールします。kubernetesではDockerはバージョン(18.06.0)が指定されているので、指定されたバージョンをインストールします。 これと違うバージョンではkubernetesが動作しないようです。

sudo su

# Install Docker CE
## Set up the repository:
### Update the apt package index
    apt-get update

### Install packages to allow apt to use a repository over HTTPS
    apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common

### Add Docker’s official GPG key
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

### Add docker apt repository.
    add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"

## Install docker ce.
apt-get update && apt-get install -y docker-ce=18.06.0~ce~3-0~ubuntu

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# Restart docker.
systemctl daemon-reload
systemctl restart docker

kubelet kubeadm kubectlのインストール

以下のコマンドをルートユーザで実行します。

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

Masterノードのcgroup driverを設定

Masterノードの場合はcfgroup driverを指定します。 今回dockerを使用するので、kubeadmが自動的に認識して/var/lib/kubelet/kubeadm-flags.env に設定してくれます。

hostsファイルにホストを設定

/etc/hostsに各ホストが名前で参照できるように、以下の行を追加してIPアドレスを設定します。

192.168.33.21  host1
192.168.33.22  host2
192.168.33.23  host3
192.168.33.24  host4

1台目(host2)からsshログインできるようにする

1台目(host2)からhost3, host4へsshログインできるように設定します。この設定は、作成した証明書やキーファイルを各ホストにコピーするために行います。

sshキー作成

rootユーザでパスワード無しのsshkeyをhost2で作成します。

vagrant@host2:~$ sudo su
root@host2:/home/vagrant# ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:VyAkqa3mKCEP0Q0h5gzGmfu6ZZ7qW7JR6r07i+gPGng your_email@example.com
The key's randomart image is:
+---[RSA 4096]----+
|+o+.  .oo .      |
|*=.   .. . .     |
| +.o o      .    |
|... o .    .     |
| ... .  S .      |
|= o.o    .       |
|+OEB             |
|=+#.o            |
|=@=O=            |
+----[SHA256]-----+
root@host2:/home/vagrant# cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys

他のホストへログインできるように設定

作成したキーファイルの公開鍵を他のホストにコピーしてhost2からsshログインできるようにします。

作成したキーを一時的に/vagrantディレクトリ(vagrantで設定されたホストと共有するフォルダ)へコピー

root@host2:/home/vagrant# cp /root/.ssh/id_rsa.pub /vagrant
oot@host2:/home/vagrant# exit
exit
vagrant@host2:~$ exit
ログアウト
Connection to 127.0.0.1 closed.

コピーしたファイルを他のホストへ設定

$ vagrant ssh host3

Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-43-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Jan 20 00:51:17 UTC 2019

  System load:  0.0               Processes:             93
  Usage of /:   14.5% of 9.63GB   Users logged in:       0
  Memory usage: 6%                IP address for enp0s3: 10.0.2.15
  Swap usage:   0%                IP address for enp0s8: 192.168.33.23


  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 個のパッケージがアップデート可能です。
0 個のアップデートはセキュリティアップデートです。


Last login: Sun Jan 20 00:02:09 2019 from 10.0.2.2

vagrant@host3:~$ cat /vagrant/id_rsa.pub >> ~/.ssh/authorized_keys

同じように、host4へもコピーします。操作は同じなので記載は省略します。

確認

host2へログインして、以下のように接続確認します。

ssh-agent起動

sudo su
root@host2:/home/vagrant# eval $(ssh-agent)
Agent pid 1044

キーを追加

root@host2:/home/vagrant# ssh-add ~/.ssh/id_rsa
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

接続

root@host2:/home/vagrant# ssh -A host3
The authenticity of host 'host3 (192.168.33.23)' can't be established.
ECDSA key fingerprint is SHA256:m4aEJu5UA1Bz/ervjgQhlJ+aYUkktASYv9krfbmV2PI.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'host3' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-43-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Jan 20 01:37:20 UTC 2019

  System load:  0.0               Processes:             96
  Usage of /:   14.0% of 9.63GB   Users logged in:       0
  Memory usage: 6%                IP address for enp0s3: 10.0.2.15
  Swap usage:   0%                IP address for enp0s8: 192.168.33.23

 * MicroK8s is Kubernetes in a snap. Made by devs for devs.
   One quick install on a workstation, VM, or appliance.

   - https://bit.ly/microk8s

 * Full K8s GPU support is now available!

   - https://blog.ubuntu.com/2018/12/10/using-gpgpus-with-kubernetes


  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 個のパッケージがアップデート可能です。
0 個のアップデートはセキュリティアップデートです。



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@host3:~# exit
ログアウト
Connection to host3 closed.
root@host2:/home/vagrant#

同じようにhost4に対しても行います。以上でClusterを構築する前準備が完了です。 次に、Clusterを構築します。続きは次の投稿で。

Kotlinはなかなか良いね

昔、KotlinがGoogleAndroid開発で正式対応されて、なんで新しい言語がそんなにみんな好きなの?と言っていた自分ですが、最近Kotlinを触り始め、これは良いと思ってしまいました。

その頃は、ちょっと不便だけどJavaでそこそこ満足しており、別に新しい言語に対応しなくてもいいんじゃね?と思っていたのですが、考えを訂正します。 Javaで開発している皆さん、Kotlinも使ってみましょう。

きっとこの言語の素晴らしさがわかるはずです。

パフォーマンスはJava系フレームワーク最強

Webフレームワークのベンチマークを掲載しているサイトを発見しました。Web Framework benchmarksというサイトです。

このサイトによると、Java系(Java/Kotlin)フレームワークは速度的に最強ということでした。 最近、速度が速いとか、関数型が好き?、流行っているとかいう理由でGo言語を使うプロジェクトも散見されますが、早さを理由に、Go言語を使う理由はないですね。

個人的にはJavaやKotlin好きですし、長年の実績があり安定したライブラリも多く、Kotlinに関しては文法も現代的で洗練されています。 よく分からないのに無理してGo言語使う理由ってなんだろう?とか思っちゃいます。

Windows 10でVagrantの仮想マシン起動時にマウントで失敗

Windows 10でVagrantを使って仮想マシンを起動したとき、/vagrantフォルダをcifsでマウントしようとして失敗します。VagrantのプロバイダーはHyper-Vです。

==> default: Mounting SMB shared folders...
    default: E:/vagrant/Debian => /vagrant
Failed to mount folders in Linux guest. This is usually because
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:

mount -t cifs -o uid=1000,gid=1000,sec=ntlm,credentials=/etc/smb_creds_06fc4a57cab5868f1a4965e043cd4a19 //192.168.1.6/06fc4a57cab5868f1a4965e043cd4a19 /vagrant

The error output from the last command was:

mount error(112): Host is down
Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)

どうも、Windows 10 Fall Creators Updateでsmb v1が無効にされたのが原因のようです。 以下のサイトに解決方法が出ていて、本質的なものかどうか疑問なのですが、Windowsでsmb v1を有効にして解決できました。

https://github.com/docksal/docksal/issues/382