#はじめに
・この記事の目的
コンテナとは何か、どうやって使うのかを手を動かして知りたいという方向けに、k8sを使ってウェブアプリを動かせるようになるまでの手順を紹介します。
一からk8sを使えるようにする方法とEKSを使った方法を記載します。
・そもそもk8sって。。。
一言にするとk8sはコンテナオーケストレーションシステムで、コンテナを管理します。
詳しい説明は以下のページがわかりやすいと個人的に思っています。
また、k8sで用いるdockerに関しては以下のページが深く説明していると思います。
EKSはAWSでk8sをマネージドサービスとして利用できるようにしたものです。
・この記事でやること、作るもの
この記事では、k8sを使える環境について、EC2でクラスターを作成する方法と、EKSでクラスターを作成する方法の2通りを記載します。
最後にk8sを使ってオブジェクトを作成し、ウェブアプリを動かしてみます。
また、すでにk8sの使い方を紹介する記事は多くあるため、この記事では自身が構築する際に注意したところに絞って記載します。
#(方法1)EC2でのクラスター作成手順
##構成図
方法1で使うリソースです。
##1.AWSリソースの作成
k8sをインストールするEC2を作成します。
過去の記事で使ったCloudFormationでEC2を作成します。
CloudFormationのスタックはS3にアップロードしたyamlファイルのURLを使って作成できます。
ただし、EC2の性能には注意します。
性能によってはk8sのノード初期化時にエラーが起きます。
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
[ERROR Mem]: the system RAM (983 MB) is less than the minimum 1700 MB
そこで、今回はEC2のインスタンスタイプを「t2.medium」とします。
作成したEC2にSSH接続できるか確認しておきます。
今後、何度も接続するので、コマンドをファイルにまとめて実行します。
この記事では、WindowsでTeratermを使って鍵とEC2のグローバルIPアドレスを指定してアクセスします。EC2にはElasticIPを使っていないのでIPアドレスを入力にします。
コマンドは以下の通りです。
chcp 65001
set /p EC2_ADDR="input addr of EC2 : "
set TERATERM_EXE="teraterm(.exe)のパス"
set KEY_FILE="鍵(.pem)のパス"
START "" %TERATERM_EXE% %EC2_ADDR% /auth=publickey /user=ec2-user /keyfile=%KEY_FILE%
上記をファイル(.bat)に記載して実行するとコマンドプロンプトで、以下の文字が出て入力待機となります。
input addr of EC2 :
EC2のグローバルIPを入力してEnterキーを押すと、Teratermが起動してEC2にSSH接続できます。
##2.dockerを実行できる環境の作成
dockerコマンドを使えるようにします。
詳しい手順は以下の記事にあります。
EC2にdockerをインストールするには以下の方法もあります。
また、この記事ではコンテナのビルドにdocker-composeを使います。
docker-composeのインストール方法は以下の記事にあります。
dockerコマンドをroot以外のユーザー(今回はec2-user)で使うには、dockerグループに加える必要があります。
sudo usermod -aG docker ec2-user
ユーザーのグループ変更を反映するには、再ログインが必要です。
インストールが完了したら、以下のコマンドでdockerのバージョンを確認することができます。
docker version
docker-compose version
##3.k8sを実行できる環境の作成
k8sをインストールして、マスターノードを作成します。
詳しい手順は以下のページにあります。
ノードを作成する際、/etc/hostsファイルにIPアドレスを記載します。
IPアドレスをコマンドで調べて記載するのは以下のコマンドでできます。
echo "`ip -4 a show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'` `hostname`" | sudo tee -a /etc/hosts
kubelet,kubeadm,kubectlをインストールするコマンドは以下のものを使いました。
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
続いて、kubeletサービスを起動しますが、kubeadmでノードを初期化するまではエラーが起きます。
<コマンド>
systemctl status kubelet
<コマンド結果>
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
mq10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Fri 2021-12-03 14:25:06 UTC; 1s ago
Docs: https://kubernetes.io/docs/
Process: 2098 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=1/FAILURE)
Main PID: 2098 (code=exited, status=1/FAILURE)
次にノードを初期化しますが、以下のエラーが起きることがあります。
<コマンド>
sudo kubeadm init
<エラー文の確認>
sudo tail /var/log/messages
<エラー文抜粋>
Dec 3 14:35:53 ip-10-0-0-105 kubelet: E1203 14:35:53.407991 6172 server.go:294] "Failed to run kubelet" err="failed to run Kubelet: misconfiguration: kubelet cgroup driver: \"systemd\" is different from docker cgroup driver: \"cgroupfs\""
Dec 3 14:35:53 ip-10-0-0-105 systemd: kubelet.service: main process exited, code=exited, status=1/FAILURE
Dec 3 14:35:53 ip-10-0-0-105 systemd: Unit kubelet.service entered failed state.
Dec 3 14:35:53 ip-10-0-0-105 systemd: kubelet.service failed.
これを解決するため、以下の記事を参考に作業します。
dockerのコントロールグループのファイルシステムを変更します。
echo '
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
' | sudo tee /etc/docker/daemon.json > /dev/null
変更後、サービスの再起動を行います。
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart kubelet
これで「sudo kubeadm init」がエラーなく実行できるようになります。
後はコマンドの案内に従ってkubeconfigファイルを作成します。
インストールしたパッケージは以下のコマンドでバージョンを確認できます。
kubelet --version
kubeadm version
kubectl version
##4.k8sのクラスターネットワークの作成
最後にクラスターネットワークを作成します。
詳細は以下の記事にあります。
#(方法2)EKSでのクラスター作成手順
##構成図
方法2で使うリソースです。
##1.AWSリソースの作成
EKSを使うためのVPCやサブネット、EKSにアクセスするためのEC2を作成します。
CloudFormationを利用します。
EKSは異なるAZの2つのサブネットが必要なので、方法1よりも作成するリソースは多くなります。
EKSが利用するサブネットのyamlを以下に示します。
#SUBNET
SnPublic:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref vpc
CidrBlock: 10.0.0.0/24
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-SnPublic'
SnPrivate:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref vpc
CidrBlock: 10.0.1.0/24
AvailabilityZone: ap-northeast-1c
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-SnPrivate'
##2.EKSクラスターの作成
AWSコンソールからEKSを作成します。
作成するためにコンソール上で以下の項目を入力します。
項目 | 値 |
---|---|
名前 | 任意の名前を入力 |
クラスターサービスロール | 適したロールを選択 |
サブネット | 作成した2つのサブネット |
クラスターエンドポイントアクセス | プライベート |
EKSが作成されると自動で、EKSが所属するセキュリティグループ(SG)も自動で作成されます。
作成されたSGはクラスターのネットワーキングのページで確認できます。
EC2からアクセスできるように、セキュリティグループのインバウンドルールに以下を追加します。
項目 | 値 |
---|---|
タイプ | すべてのTCP |
ソース | EC2のローカルIPアドレス |
EKS作成で必要なIAMロールは以下のページから確認できます。
※今回はノードグループは使いませんが、作成する場合には以下のページに説明のあるIAMロールが必要です。
##3.dockerを実行できる環境の作成
EKSへアクセスするEC2でdockerのコマンドを使えるようにします。
方法1と同様の手順です。
##4.k8sコマンドを実行できる環境の作成
EKSへアクセスするEC2でk8sのコマンドを使えるようにします。
k8sコマンドを使うにはkubectlをインストールします。
詳しい手順は以下のページにあります。
どのバージョンのkubectlをインストールするかは、k8sのバージョンとEC2のCPUのベンダーから判断します。
k8sのバージョンはEKSのページから確認できます。
CPUのベンダーは以下のコマンドで表示されるvender_idから判断します。
cat /proc/cpuinfo
今回はk8sのバージョンが1.21でCPUのベンダーがIntelなので、以下のコマンドでkubectlをインストールします。
curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.21.2/2021-07-05/bin/linux/amd64/kubectl
次に、awsコマンドからEKSに接続するための設定をします。
awsコマンドを使うにはアクセスキーの設定をします。コマンド「aws configure」で設定できますが、今回はファイルへ直接書き込みます。
mkdir -p /home/ec2-user/.aws
echo "
[default]
output = json
region = ap-northeast-1
" > /home/ec2-user/.aws/config
echo "
[default]
aws_access_key_id = awsのアクセスキー
aws_secret_access_key = awsのシークレットアクセスキー
" > /home/ec2-user/.aws/credentials
EKSに接続するためには、接続先を記したkubeconfigファイルを作成します。
詳細な手順は以下のページにあります。
$HOME/.kube/configファイルには以下の情報が書かれています。
・クラスター(clusters)
・ユーザー(users)
・コンテキスト(contexts)
・現在設定されているコンテキスト(current-context)
現在設定されているコンテキストを表示するには以下のコマンドを使用します。
kubectl config get-contexts
##5.ECRの作成と接続
k8sで使うコンテナイメージの保存先であるECRの作成とEC2からの接続を行います。
まず、ECRをAWSコンソールから作成します。
ECRの作成ページから以下の項目を入力して作成します。
項目 | 値 |
---|---|
可視性設定 | プライベート |
リポジトリ名 | 任意の名前を入力 |
次にECRへ接続します。
詳細な手順は以下のページにあります。
ECRへ接続するための情報は/home/ec2-user/.docker/config.jsonに記載されます。
ECRへコンテナイメージをプッシュする方法は以下のページにあります。
#k8sでウェブアプリの実行とアクセス
k8sにオブジェクトを作成し、コンテナ内でウェブアプリを動かしてみます。
今回は、方法1で作成したEC2内で作業します。
動かすウェブアプリは過去の記事で作成したものを使います。
##1.dockerのコンテナイメージの作成
コンテナのイメージはcentosを基に作成します。そのため、以下のコマンドでEC2にcentosのイメージをダウンロードします。
docker pull centos:centos7
ビルド時の動作を記述するDockerfileを作成します。
Dockerfileの詳細は以下のページにあります。
Dockerfileにはソースファイルをコピーする処理を記述します。
ファイルはすべて/home/ec2-user/sourceディレクトリに入っているものとします。
ENV workdir /myapp
ENV srcdir .
ADD $srcdir $workdir
docker-composeで使うyamlファイルを作成します。
version: "3"
services:
web:
build: .
image: centos:myimg
tty: true
docker-composeコマンドでビルドします。
docker-compose build
※ビルド後は以下のコマンドでコンテナを立ち上げることができます。
docker-compose up -d
##2.k8sでのウェブアプリの実行
k8sでオブジェクトを作成し、ウェブアプリを実行します。
この記事ではマスターノードにオブジェクトを作成します。
そのため、マスターノードへのPODのデプロイを許可します。
MASTER_NODE=`kubectl get node | grep master | cut -d' ' -f1`
kubectl taint nodes $MASTER_NODE node-role.kubernetes.io/master:NoSchedule-
詳細な手順は以下のページにあります。
次にPODをデプロイするためのyamlファイルを作成します。
apiVersion: v1
kind: Pod
metadata:
name: mypod
labels:
app: webapp
spec:
containers:
- name: webapp
image: centos:myimg
tty: true
ports:
- containerPort: 8080
yamlファイルを基にPODを作成します。
kubectl apply -f 作成したyamlファイル
POD内のウェブアプリをk8s外からアクセスするためのserviceオブジェクトを作成します。
yamlファイルは以下の通りです。serviceオブジェクト作成のコマンドはPOD作成時と同じものとなります。
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- name: webapp
port: 8080
nodePort: 30001
selector:
app: webapp
type: LoadBalancer
作成したPODにログインして、ウェブアプリを実行します。
以下のコマンドでPODにログインします。
kubectl exec -it mypod -- /bin/bash
ウェブアプリの実行手順は過去の記事を基に記載します。
まず、以下のコマンドでjavaをインストールします。
#javaインストールのために必要なパッケージのインストール
sudo yum install -y wget
#javaのインストール
mkdir -p $HOME/java-tmp/jdk
mkdir -p $HOME/.java/jdk
wget https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz -O $HOME/java-tmp/jdk-pkg
tar xzvf $HOME/java-tmp/jdk-pkg -C $HOME/java-tmp/jdk
cp -r $HOME/java-tmp/jdk/`ls $HOME/java-tmp/jdk/`/* $HOME/.java/jdk
export JAVA_HOME=$HOME/.java/jdk
export PATH=$PATH:$JAVA_HOME/bin
echo '
export JAVA_HOME=$HOME/.java/jdk
export PATH=$PATH:$JAVA_HOME/bin
' >> $HOME/.bashrc
yes | rm -r $HOME/java-tmp
以下のコマンドでウェブアプリを実行します。
java -jar jarファイル
ウェブアプリが動いているかの確認は、EC2上とEC2にログインするために使っているローカルPC上で行えます。
EC2上で行うには、EC2にログイン後、以下のコマンドを実行します。
ステータスコードが200で帰ってくると思います。
curl -I http://localhost:30001
ローカルPC上で行う方法は以下の通りです。
Windowsの場合はコマンドプロンプトで以下を実行します。
ssh -i pemファイル -L 18080:localhost:30001 ec2-user@EC2のグローバルIPアドレス -N
次にブラウザにて、以下のURLにアクセスするとウェブアプリにアクセスできることが確認できます。
http://localhost:18080
#終わりに
今回は業務でKubernetes(k8s)に触れる機会があり、学んだことと気になったことをまとめる意味で記事を作成しました。
k8sの構築について、EC2の方法と、EKSの方法を比較すると、EKSの方が手を動かす量は少なく感じました。
しかし、EKSを使う場合にはIAMロールを考える必要があり、EC2の方が必要なAWSのリソースは少ないと感じました。
学べば学ぶほどk8sは深いなーと感じました。
手を動かすと知識を深く学ぶことができて、楽しいです!