はじめに
- ネットワークまわりを確認&勉強しながら、Kubernetesの環境構築をしたときのメモです。
- 構築手順自体は、Ubuntu 18.04 LTS にKubernetes環境をインストールする [Master / Worker]の通りに実施したところ、サクッとできました。
構成概要
構成図
- 今回構築した環境は下記の通りです。
- AWSでEC2を3台立てて検証しました。
補足
- EC2を配置しているVPCにはIGWを関連付けている
- EC2を配置しているVPCのIPレンジとして10.1.100.0/16を設定している
- flannelのIPレンジは、デフォルトのbridege(172.17.0.0/16など)と被らないよう設定する必要がある
- 今回は、172.21.0.0/16を指定した
- ホストに複数のNICが接続されている場合は、他のクラスタノードと通信するNICを、 kubeadm init --apiserver-advertise-address で指定する(今回は1枚)
- 起動したPodに対して、ユーザ(インターネット経由)は http://18.176.61.21:30000 などでアクセスできる
構築手順
[Ctrl/Node] EC2作成
- 2CPU/メモリ2GB以上でOSが対応していれば良さそう
* セキュリティグループ作成
* ローカルPCからのssh
* 下記インスタンス間のtcp(プライベートIP)
* インスタンス作成
* Ubuntu Server 18.04 LTS
* t2.medium
[Ctrl/Node] Dockerをインストール
# 必要なライブラリを事前にインストール
$ sudo apt update
$ sudo apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# GPG公開鍵のインストール
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 公開鍵のフィンガープリントを確認
$ sudo apt-key fingerprint 0EBFCD88
# aptリポジトリの設定
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# dockerインストール
$ sudo apt update
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# 動作確認
$ sudo docker run --rm hello-world
$ sudo docker rmi hello-world
[Ctrl/Node] kubeadmをインストール
# GPG公開鍵のインストール
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
# aptリポジトリの設定(Googleが提供しているパッケージリポジトリを登録)
$ sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
# kubeadmインストール
$ sudo apt update
$ sudo apt install -y kubeadm
# swapをオフにする
# これだとOS再起動の度に必要になるので、/etc/fstabファイルを編集するのがよい
$ sudo swapoff -a
[Ctrl] Kubernetesをセットアップ
# コントロールプレーンのセットアップ
# etcd、apiserver、controller-manager、schedulerといったコンテナを起動するなど、色々
# --apiserver-advertise-address: 他ノードと接続できるネットワークインターフェイスに割り当てられているIPアドレスを指定する
# --pod-network-cidr: KubernetesのPod(コンテナ)に割り当てるIPアドレス範囲
# 上手くいかなかった場合、 kubeadm reset を実行して設定をリセットしてから再度実行する
$ sudo kubeadm init --apiserver-advertise-address=10.1.100.11 --pod-network-cidr=172.21.0.0/16
# kubectlコマンド設定ファイルの配置
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
# ノード確認
# ネットワーク関連の設定が完了していないため、STATUSはNotReadyでよい
$ kubectl get nodes
# flannelのセットアップ
# コンテナ間の通信を行うための仮想ネットワーク
# flannelのためにiptablesを編集
$ sudo sysctl net.bridge.bridge-nf-call-iptables=1
# 設定ファイルの取得、修正
$ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# net-conf.json: 以下の ”Network” の値を、kubeadm initコマンド実行時に --pod-network-cidr オプションで指定したものに変更する
$ vim kube-flannel.yml
---
"Network": "172.21.0.0/16",
---
# flannelの作成
$ kubectl apply -f kube-flannel.yml
# ノード確認
$ kubectl get nodes
# (参考)クラスタを作り直す場合、上記で作成した仮想インターフェイスを一旦削除しておく
# ip link delete cni0, ip link delete flannel.1
[Node] クラスタにjoinする
# クラスタにjoinする
$ sudo kubeadm join 10.1.100.11:6443 --token xxxxxx.xxxxxxxxxxxxx --discovery-token-ca-cert-hash sha256:xxxxxxx
# ノード確認(コントロールプレーンにて実行)
$ kubectl get nodes
[Ctrl]JupyterNotebookコンテナを作成・接続
- マニュフェストファイル作成 -> 実行
- コマンドだと、 docker run -p 10000:8888 --name jupyter docker.io/jupyter/scipy-notebook
notebook.yaml
# Deployment
# アプリケーションの配布単位を管理するリソース
# ReplicaSetを管理する(ReplicaSetの履歴を持つ)
# ReplicaSet: 指定された数のPodを複製し、実行してくれる
apiVersion: apps/v1 # APIのバージョン情報
kind: Deployment # リソースの種類
metadata:
name: test-notebook # リソースの名前
spec: # リソースの詳細
selector: # ここで指定したPodを起動する
matchLabels:
app: notebook # Podのテンプレートを指定する([A])
replicas: 1 # クラスタ内で起動するPodの数
template: # 作成される(動かしたい)Podのテンプレート
metadata:
labels:
app: notebook # PodにLabelを付ける([A]と対応)
spec:
containers:
- name: notebook # コンテナ名
image: docker.io/jupyter/scipy-notebook # コンテナイメージの場所
ports:
- containerPort: 8888 # ポート番号
---
# Service
# クラスタ内のPodに対して、クラスタ内部および外部のネットワークからアクセスするためのリソース
# Selectorで選択したPodをUpstreamとしたLB
apiVersion: v1 # APIのバージョン情報
kind: Service # リソースの種類
metadata:
name: test-service # リソースの名前
spec: # リソースの詳細
type: NodePort # [ClusterIP, NodePort, LoadBalancer, ExternalName]
selector: # ここで指定したLabelが付与されているPodに伝送する
app: notebook # ([A]と対応)
ports:
- port: 8888 # ポート番号
# Podのデプロイ
$ kubectl create -f notebook.yaml
# ポート確認
$ kubectl get svc
# logを見てtoken確認
$ kubectl get pod
$ kubectl logs XXX
# -> http://:<30000台のポート>/ でアクセス可能
メモ
確認に使ったコマンド
- NW
# IP確認
$ ip addr show
# NIC確認
$ ifconfig
# iptables確認
$ sudo iptables -nL
# ルートテーブル確認
$ route
- Kubernetes
# クラスタ確認
$ kubectl cluster-info
# ノード確認
$ kubectl get nodes
$ kubectl get nodes -o==wide
$ kubectl describe node XXX
# ポッド確認
$ kubectl get pod
$ kubectl get pod -o wide
$ kubectl get pod --show-labels
$ kubectl get pod -l env=prod
$ kubectl describe pod XXX
$ kubectl logs XXX
# サービス確認
$ kubectl get svc
# まとめて確認(Deployment, ReplicaSet, Pod, Service)
$ kubectl get all
ネットワークについて
-
AWS
- グローバルIPがOSから(ifconfigで)見えない
- グローバルIPは、コンソールのネットワークインターフェイスのプロパティとして表示されるが、実態はNATによってプライベートIPにマッピングされている。
- グローバルIPがOSから(ifconfigで)見えない
-
Docker
- コンテナとして起動するサービスを外部に公開する場合は、コンテナホストの特定ポートに対するアクセスをコンテナに対してiptablesによりDNATすることで、コンテナに対するアクセスを実現している。
-
Kubernetes
- flannel
- Docker単体での利用との違いは、ノードを跨ぐこと。各Podにはノードごとに独立したIPアドレスが割り当てられるが、ノード跨ぎの場合は課題が発生する。Docker単体ではNATを利用しているが、Pod作成の度にNATテーブルを操作するのは効率的ではないため、オーバーレイネットワークを採用している。
- 詳細はわかった気になるflannelの仕組みが分かりやすい
- flannel