はじめに
久しぶりの投稿です。
今回は社内で使っている機械学習機の自動構築基盤の構築メモになります。
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 |
自作したサーバ
2. ネットワーク
構築するネットワーク構成は以下の図とする。
MachineLearning用のPC(PC)を自動構築する。
3. ミドルウェア
ミドルウェア構成は以下の様にする。
MAASサーバからMAASクライアント(MLP(機械学習基盤))に自動構築させる。
構築フロー
MAAS(ベアメタル)作業
① OSのインストール
MAASサーバにするマシンにOSをインストールする。
OSはUbuntu18.04にする。
・ubuntuダウンロード
以下のURLからUbuntu ServerのISOイメージをダウンロードする.
・Ubuntuイメージの起動ディスク作成
手持ちのUSBメモリにUbuntuのISOイメージを焼き付けて、インストール用メディアを作成する.
・USBメモリの確認
MACにUSBメモリを差した後、ターミナルを立ち上げディスクの場所を確認する.
diskutil list
コマンド実行時は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の設定
ログイン画面が出てくるため、
作成したユーザーでログイン.
ログイン後、イントロページが出てくる.
特に設定をいじる必要はない.
後者の画像では、ダウンロードするUbuntuのOSイメージを選択する.
欲しいバージョンにチェックを入れたら、基本的に自動でダウンロードが始まるため、しばらく待つ.
ダウンロードが完了し、「Status」が「Synced」になったらContinueをクリック
秘密鍵を入力する画面に移るため、Ubuntuサーバー側で鍵を生成する.
特に指定はせずに、空欄のままエンター連打.
$ sudo ssh-keygen -t rsa
サーバーの.sshフォルダに鍵が生成されるため、
そちらの公開鍵の中身をコピーする.
cat .ssh/id_rsa.pub
コピー後はMAASの管理サーバーに戻り、SourceをUploadに変え、隣の入力画面に先ほどコピーした鍵の中身をペーストし、Importをクリック.
問題がなければ「Go to dashboard」をクリック.
準備として、MAASトップページ上部の「Subnets」ページ内、展開したいネットワークVLANのuntaggedを選択.
画面上部の「Take action」から「Provide DHCP」を選択.
MAASサーバーのDHCPレンジが出てくるため、任意の数を指定し、「Provide DHCP」を選択すると、同じページ内のDHCP項目がEnableになり、「Reserved ranges」に追加したネットワーク範囲が表示される.
これで一通りの下準備が完了になる.
④ MAASクライアントにOSデプロイ
MAASクライアントとなる端末のBOOT順序でPXE bootの項目を起動順序の一位へする.
その後クライアントの電源を入れると自動でMAASサーバーと通信を開始し、電源が落ちる.
電源が落ちた後は、MAASの管理画面上の「Machines」に端末が追加される.
(端末の名前は仮で動物の名前が入る)
「Configration」内の「Power configuration」で電源オプションを選択.
今回は「Manual」を選択する.
「Machines」ページで、端末のチェックボックスにチェックを入れ、「Take action」から「Commission」を選択した後、クライアント端末の電源を入れる.
再びサーバーとの通信を開始するので終了まで待つ.
無事にCommissionが終了したら、サーバーの管理画面では「Status」が「Ready」になる.
「Take action」から「Deploy」を選択し任意のOSを選択し、デプロイを開始させ、クライアントの電源を入れる.
サーバーからOSがデプロイされるため、しばし待ち、管理画面上でStatus欄がOS名に変われば成功
クライアント端末のネットワーク設定について
MAASのクライアント端末は基本はDHCPだが、Staticに指定することも可能.
その場合はOSのデプロイ前に端末の情報ページ内「Interfaces」内の「Actions」-「Edit Physical」を選択し、「Auto assign」を「Static」に変更し、任意のアドレスを指定する.
MAASのクライアント端末は基本はDHCPだが、Staticに指定することも可能.
その場合はOSのデプロイ前に端末の情報ページ内「Interfaces」内の「Actions」-「Edit Physical」を選択し、「Auto assign」を「Static」に変更し、任意のアドレスを指定する.
⑤ 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
ここで下記スペックの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
ログインするためのトークンを発行する
$ 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
お疲れ様でした!!
#さいごに
この環境構築はGAUSSインフラチームで構築しました!!
@monkeydaichan
@tsukasa1301
今後もどんどん記事更新していきますのでフォローよろしくお願いいたします。
なお、アプリチームはTypescript + ReactでAPIとSPAの新フレームワーク構築してますのでそちらも継続して見てください!
twitterやってます。
フォローお願いします。
※※※ 人工知能で競馬予想sivaを運用しています。
連対的中率 : 約 86%
回収率 : 約 136%