Edited at

[業務で使える!]Kubernetes(Docker)、Ansibleを使った機械学習基盤の構築自動化(ベアメタル)メモ

More than 1 year has passed since last update.


はじめに

久しぶりの投稿です。

今回は社内で使っている機械学習機の自動構築基盤の構築メモになります。

twitterやってます。

フォローお願いします。

※※※ 人工知能で競馬予想sivaを運用しています。

連対的中率 : 約 86%

回収率 : 約 136%

今回の環境構築はGAUSSのインフラチームで構築しました!!

@monkeydaichan

@tsukasa1301

今後もどんどん記事更新していきますのでフォローよろしくお願いいたします。

また、アプリチームはTypescript + ReactでAPIとSPAの新フレームワーク構築してますので、そちらもQiitaに書きます!!


目的

以下の二点を目標として環境構築します。

① 機械学習環境構築の自動化する。(MAAS / Ansible)

② エンジニアPoC用のDockerコンテナの利用を目的とする。 (Kubernetes)

[背景(課題)]

サーバ増強するたびに環境構築が大変。

サーバ(端末)によって環境差異が発生してしまう。

社内のエンジニアのサーバーの使用状況がわかりにくい。


機械学習マシン構成


1. スペック

以下のPCを8台準備

 
 

CPU
Intel Core i7-8700K(6コア、12スレッド)

MEM
DDR4 32G

GPU
ASUS NVIDIA GTX1070ti * 2


自作したサーバ

IMG_1058.JPG


2. ネットワーク

構築するネットワーク構成は以下の図とする。

MachineLearning用のPC(PC)を自動構築する。

network.png


3. ミドルウェア

ミドルウェア構成は以下の様にする。

MAASサーバからMAASクライアント(MLP(機械学習基盤))に自動構築させる。

mw.png


構築フロー

flow.png


MAAS(ベアメタル)作業


① OSのインストール

MAASサーバにするマシンにOSをインストールする。

OSはUbuntu18.04にする。


・ubuntuダウンロード

以下のURLからUbuntu ServerのISOイメージをダウンロードする.

http://releases.ubuntu.com/18.04/


・Ubuntuイメージの起動ディスク作成

手持ちのUSBメモリにUbuntuのISOイメージを焼き付けて、インストール用メディアを作成する.


・USBメモリの確認

MACにUSBメモリを差した後、ターミナルを立ち上げディスクの場所を確認する.

diskutil list

スクリーンショット 2018-05-20 19.18.13.png

コマンド実行時はUSBメモリは/dev/disk2となっていたので、これを一度MS-DOS形式でフォーマットする.

diskutil eraseDisk MS-DOS UNTITLED /dev/disk2

フォーマットされたUSBメモリをアンマウントしddコマンドで起動ディスクを作成する.

diskutil unmountDisk /dev/disk2

sudo dd if=./Downloads/ubuntu-18.04-live-server-amd64.iso of=/dev/disk2 bs=4028

多少時間がかかるため、コーヒータイム.

イメージ作成が完了したら、デバイスを取り外す.

もし刺さったままなら、

diskutil eject /dev/disk2

を実行してUSBメモリを抜く.


・Ubuntuイメージのインストール

MAASサーバ用の端末に先ほど作成したUSBを差し、BOOT画面でUSB起動を指定しインストールを開始.

BOOTデバイスの指定はマシンによって異なるため省略.

インストールのオプションは任意の設定で.


② MAASインストール

サーバーにMAASパッケージをインストールする.

$ sudo apt -y update

$ sudo apt -y upgrade
$ sudo apt -y install maas

インストールが完了したら管理者用ユーザの作成.

必要なユーザー名、パスワード、アドレスなどを設定.

SSHキーの登録は後で行うため、空欄のままエンターでスルー.

$ sudo maas createadmin

作成が完了したら「MAASサーバーのアドレス:5240/MAAS/」でログイン.


③ MAASの設定

ログイン画面が出てくるため、

作成したユーザーでログイン.

スクリーンショット 2018-05-22 14.24.41.png

ログイン後、イントロページが出てくる.

特に設定をいじる必要はない.

後者の画像では、ダウンロードするUbuntuのOSイメージを選択する.

欲しいバージョンにチェックを入れたら、基本的に自動でダウンロードが始まるため、しばらく待つ.

ダウンロードが完了し、「Status」が「Synced」になったらContinueをクリック

スクリーンショット 2018-05-22 14.24.59.png

スクリーンショット 2018-05-22 14.25.20.png

秘密鍵を入力する画面に移るため、Ubuntuサーバー側で鍵を生成する.

特に指定はせずに、空欄のままエンター連打.

$ sudo ssh-keygen -t rsa

サーバーの.sshフォルダに鍵が生成されるため、

そちらの公開鍵の中身をコピーする.

cat .ssh/id_rsa.pub

コピー後はMAASの管理サーバーに戻り、SourceをUploadに変え、隣の入力画面に先ほどコピーした鍵の中身をペーストし、Importをクリック.

問題がなければ「Go to dashboard」をクリック.

スクリーンショット 2018-05-22 14.25.54.png

準備として、MAASトップページ上部の「Subnets」ページ内、展開したいネットワークVLANのuntaggedを選択.

スクリーンショット 2018-05-23 12.28.03.png

画面上部の「Take action」から「Provide DHCP」を選択.

スクリーンショット 2018-05-23 12.32.09.png

MAASサーバーのDHCPレンジが出てくるため、任意の数を指定し、「Provide DHCP」を選択すると、同じページ内のDHCP項目がEnableになり、「Reserved ranges」に追加したネットワーク範囲が表示される.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f64616464393437352d626531372d663134302d343534662d3738653037616661623833342e706e67.png

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f61386132633162382d666161392d373463342d343033302d6465343265633232393032652e706e67.png

これで一通りの下準備が完了になる.


④ MAASクライアントにOSデプロイ

MAASクライアントとなる端末のBOOT順序でPXE bootの項目を起動順序の一位へする.

その後クライアントの電源を入れると自動でMAASサーバーと通信を開始し、電源が落ちる.

電源が落ちた後は、MAASの管理画面上の「Machines」に端末が追加される.

(端末の名前は仮で動物の名前が入る)

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f39303965386538342d303465642d316430392d623232342d3663613962366132383333352e706e67.png

追加されたマシンを選択し、まずは名前の変更をする.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f32366162613330652d373034352d313963662d323831332d3630303036356336396365362e706e67.png

「Configration」内の「Power configuration」で電源オプションを選択.

今回は「Manual」を選択する.

スクリーンショット 2018-05-23 16.03.41.png

「Machines」ページで、端末のチェックボックスにチェックを入れ、「Take action」から「Commission」を選択した後、クライアント端末の電源を入れる.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f66666561643063632d323034382d313363342d386665652d3363303734316634656464362e706e67.png

再びサーバーとの通信を開始するので終了まで待つ.

無事にCommissionが終了したら、サーバーの管理画面では「Status」が「Ready」になる.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f35316137386634322d373239632d333466652d386265312d6133303934666434366330632e706e67.png

「Take action」から「Deploy」を選択し任意のOSを選択し、デプロイを開始させ、クライアントの電源を入れる.

サーバーからOSがデプロイされるため、しばし待ち、管理画面上でStatus欄がOS名に変われば成功

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f66633432313464632d663562382d643934382d653133302d3335616265613531353863312e706e67.png


クライアント端末のネットワーク設定について

MAASのクライアント端末は基本はDHCPだが、Staticに指定することも可能.

その場合はOSのデプロイ前に端末の情報ページ内「Interfaces」内の「Actions」-「Edit Physical」を選択し、「Auto assign」を「Static」に変更し、任意のアドレスを指定する.

MAASのクライアント端末は基本はDHCPだが、Staticに指定することも可能.

その場合はOSのデプロイ前に端末の情報ページ内「Interfaces」内の「Actions」-「Edit Physical」を選択し、「Auto assign」を「Static」に変更し、任意のアドレスを指定する.

スクリーンショット 2018-05-22 13.54.10.png

スクリーンショット 2018-05-22 13.54.26.png


⑤ KVM(仮想環境)のインストール

Ansibleサーバー、k8sサーバーを作るためのKVMを土台となるMAASサーバーにインストールする

インストール後はlibvirtグループに参加し、sudoなしでも実行できるようにする

$ sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager bridge-utils

$ sudo systemctl enable libvirt-bin
$ sudo gpasswd libvirtd -a <username>

KVMの作成はデスクトップ環境を使用した方が便利なため、MAASサーバーにデスクトップをインストールする

$ sudo apt -y install ubuntu-desktop

デスクトップのインストールは時間がかかるためしばし待つ

インストールが完了して再起動すれば自動でデスクトップが表示される

デスクトップ上のターミナルでKVMを起動すれば作成用ウィンドウが起動される

$ virt-manager

0001_New-Virtual-Machine.png

ここで下記スペックのKVMを新規作成する

ホスト名:Ansible

メモリ:4GB
CPU:2
ストレージ:30GB

ホスト名:k8s-master
メモリ:8GB
CPU:4
ストレージ:40GB


⑥ Ansibleの構築

KVMで作成したAnsibleサーバーに実際にAnsibleをインストールする

$ sudo apt-get update

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible


⑦ Kubernetes Master(k8s-master)インストール


k8sのクライントが配置されるネットワークの準備をする

k8s-masterとworkerは別のネットワークにするため、Nicを追加して別セグメントを用意する。

/etc/netplan/50-cloud-init.yaml_bkの記述だけでいけるはずだったが、ブリッジの設定がうまくいかなかったため今回は2種類のファイルに記述している

$ sudo vi /etc/netplan/50-cloud-init.yaml_bk

network:
ethernets:
enp0s31f6:
addresses:
- 192.168.100.152/24
gateway4: 192.168.100.1
nameservers:
addresses:
- 8.8.8.8
search:
- 8.8.4.4
enp2s0:
addresses:
- 192.168.200.1/24
gateway4: 192.168.100.1
nameservers:
addresses:
- 8.8.8.8
search:
- 8.8.4.4
version: 2

$ sudo vi /etc/network/interfaces
auto lo
iface lo inet loopback

auto enp0s31f6
iface enp0s31f6 inet manual

auto br0
iface br0 inet static
address 192.168.100.152
netmask 255.255.255.0
gateway 192.168.100.1
dns-nameservers 8.8.8.8
bridge_ports enp0s31f6
bridge_maxwait 0
bridge_df 0
bridge_stp off

auto enp2s0
iface enp2s0 inet static
address 192.168.200.1
netmask 255.255.255.0
gateway 192.168.100.1
dns-nameservers 8.8.8.8

$ ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.100.152 netmask 255.255.255.0 broadcast 192.168.100.255
inet6 fe80::329c:23ff:feac:5570 prefixlen 64 scopeid 0x20<link>
ether 30:9c:23:ac:55:70 txqueuelen 1000 (Ethernet)
RX packets 9579059 bytes 16579553543 (16.5 GB)
RX errors 0 dropped 657286 overruns 0 frame 0
TX packets 6047022 bytes 936298283 (936.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

enp0s31f6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::329c:23ff:feac:5570 prefixlen 64 scopeid 0x20<link>
ether 30:9c:23:ac:55:70 txqueuelen 1000 (Ethernet)
RX packets 21689196 bytes 26237413396 (26.2 GB)
RX errors 0 dropped 475 overruns 0 frame 0
TX packets 6555651 bytes 4057603928 (4.0 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xdf100000-df120000

enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.200.1 netmask 255.255.255.0 broadcast 192.168.200.255
inet6 fe80::6a05:caff:fe66:a834 prefixlen 64 scopeid 0x20<link>
ether 68:05:ca:66:a8:34 txqueuelen 1000 (Ethernet)
RX packets 6867754 bytes 970026556 (970.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13304857 bytes 15246678579 (15.2 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 17 memory 0xdf0c0000-df0e0000

また2つのネットワークで通信できるようにNATの設定をする

sudo iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -j SNAT --to 192.168.100.152


k8s-masterの構築(playbook作成〜実行)

k8s-masterにk8sをインストールするためのplaybookを作成する

$ sudo vi k8s-master.yaml

---
- hosts: k8s-master
remote_user: $user名
become: yes
tasks:
- name: Install prerequisites and Docker.io #dockerインストール
become: yes
apt: name={{item}} update_cache=yes
with_items:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- docker.io
- name: user add to docker group
user: name=gauss group=docker append=yes
- name: Add K8S GPG key #k8sインストール準備
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
- name: Add K8S APT repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
- name: Install K8S
apt: name={{item}} update_cache=yes
with_items:
- kubelet
- kubeadm
- kubectl
- name: Remove swapfile from /etc/fstab #swapを消しておかないと失敗する
mount:
name: swap
fstype: swap
state: absent
- name: Disable swap
command: swapoff -a
when: Ansible_swaptotal_mb > 0
- name: Set docker service to start on boot. #再起動後もdockerを自動起動させる
service: name=docker enabled=yes
- name: Set kubelet service to start on boot. #再起動後もk8sを自動起動させる
service: name=kubelet enabled=yes
- name: Init k8s-master #k8smの初期化
become: yes
shell: kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.200.2
- name: Make Directory .kube
file:
path: /.kube
state: directory
owner: $オーナー
group: docker
mode: 0755
- name: Copy the .kube config
become: yes
file:
src: /home/$ユーザ名/Ansible/admin.conf
dest: ~/.kube/config
owner: $オーナー
group: docker
mode: 0600
- name: Export Kubernetes
lineinfile:
path: /home/$ユーザ名/.kube/config
state: absent
regexp: '^%KUBECONFIG'
- name: Apply Flannel $flannelのネットワークを作成
sudo: yes
shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml

次はAnsibleのhostsを追加設定

$ sudo vi /etc/Ansible/hosts

[master]
k8s-master

$ sudo vi /etc/hosts
192.168.100.2 k8s-master

準備ができたらAnsibleのplaybook実行

python3をしようする場合は"-e"以降のオプションが必要

~/Ansible$ sudo Ansible-playbook --private-key=id_rsa_common k8s-master.yml -e 'Ansible_python_interpreter=/usr/bin/python3'

エラーが出なければ完了


⑧ Kubernetes Clientのインストール(workerの追加)

k8sのworkerを追加するにはマスターの場合とほとんど変わらないがflannelネットワークに参加させる最後に起動させるコマンドが必要になる

そのコマンドはkubeadm initを行なった際の出力内容に表示されるが、下記コマンドでも確認することができる

(k8s-master)$ kubeadm token create --print-join-command

出てきたコマンドを使ってworker参加用のplaybookを作成する

(Ansible)$ sudo vi mlp.yml

---
- hosts: mlp01
remote_user: ubuntu
become: yes
tasks:
- name: Install prerequisites and Docker.io , nfs-common
apt: name={{item}} update_cache=yes
with_items:
- nfs-common
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- docker.io
- name: user add to docker group
user: name=ubuntu group=docker append=yes
- name: Add K8S GPG key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
- name: Add K8S APT repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
- name: Install K8S
apt: name={{item}} update_cache=yes
with_items:
- kubelet
- kubeadm
- kubectl
- name: Remove swapfile from /etc/fstab
mount:
name: swap
fstype: swap
state: absent
- name: Disable swap
command: swapoff -a
when: Ansible_swaptotal_mb > 0
- name: Set docker service to start on boot.
service: name=docker enabled=yes
- name: Set kubelet service to start on boot.
service: name=kubelet enabled=yes
- name: Join k8s-master
become: yes
shell: kubeadm join 192.168.100.3:6443 ~~ #上記のコマンドで出力したものを記述

マスターの時と同様にhostsの編集

$ sudo vi /etc/Ansible/hosts

[master]
k8s-master

[mlp]
mlp01

$ sudo vi /etc/hosts
192.168.100.3 k8s-master
192.168.200.2 mlp01

Ansibleのplaybook実行

python3をしようする場合は"-e"以降のオプションが必要

~/Ansible$ sudo Ansible-playbook --private-key=id_rsa_common mlp.yml -e 'Ansible_python_interpreter=/usr/bin/python3'

playbookが成功した場合、以下の状態になる

(k8s-master)$ kubectl get node

NAME STATUS ROLES AGE VERSION
k8s-master Ready master 3d v1.10.3
mlp01 Ready <none> 3d v1.10.2

ここでインストール(構築作業)は完了です!!


k8sでdockerイメージを走らせる(テスト)


nginxイメージの起動

nodeが追加された後は、ひとまずnginxのdockerイメージを走らせる

理由は後述する

$ sudo vi nginx-pod.yaml

apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80

$ kubectl apply nginx-pod.yaml
create
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 3d

nginxがRunningになれば問題ない


Dash-boardのインストール

Dash-boardはなくても、kubernetesを使う上ではなんとかなるがせっかくなら使いたい

というわけでインストールをしていく

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

エラーが出ず、「created」と表示されればOK

動いているかを確認

kubectl get pods --all-namespaces

NAMESPACE NAME READY STATUS RESTARTS AGE
default nginx-pod 1/1 Running 0 3d
kube-system kubernetes-dashboard-7d5dcdb6d9-7hptz 1/1 Running 0 3d

kubeのproxyを起動

$ kubectl proxy --address 0.0.0.0 --accept-hosts '.*'

Starting to serve on [::]:8001

この状態になったらブラウザでアクセスして見る

ログイン画面が出てくる

http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login

スクリーンショット 2018-05-29 14.24.06.png

ログインするためのトークンを発行する

$ kubectl -n kube-system get secret

発行されたトークンを使えば入れる

毎回トークンを発行するのが大変という人向けの設定は以下のもの

これを実行した後は、ログイン画面のSKIPで入れるようになる

ただしセキュリティ的にはガバガバなため、社内オンリーの環境など外部の人がいない条件での使用推奨

$ cat <<EOF | kubectl create -f -

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
EOF

お疲れ様でした!!

IMG_1073.JPG


さいごに

この環境構築はGAUSSインフラチームで構築しました!!

@monkeydaichan

@tsukasa1301

今後もどんどん記事更新していきますのでフォローよろしくお願いいたします。

なお、アプリチームはTypescript + ReactでAPIとSPAの新フレームワーク構築してますのでそちらも継続して見てください!

twitterやってます。

フォローお願いします。

※※※ 人工知能で競馬予想sivaを運用しています。

連対的中率 : 約 86%

回収率 : 約 136%