EKSを利用してKubernetesでSpring MVCをデプロイ(NLB + Auto Scaling)
ここではEKSを利用して、NLB配下にAutoScalingで起動するアプリケーションを起動するときの例について取り上げます。既にマネジメントコンソールやeksctlコマンドを通してクラスターは起動状態であるものとします。
PodがWorkloadsリソースの最小単位となります。それに対してReplicaSetによりPodのレプリカが作成され、指定した数のPodを維持し続けるようにします。そして、Deploymentが複数のReplicaSetを管理することで、ローリングアップデートやロールバック等を実現します。
MySQLやRedisのユーザー名やパスワード情報ははKubernetesのSecretの機能を利用してWebアプリケーションに渡します。 KubernetesのSecretでは環境変数として渡す方法とVolumeとしてマウントする方法がありますが、ここではSpring MVCのアプリケーションに対して環境変数として渡す方法について取り上げます。
以下の3つに分けて説明を行います。EKS以外のプラットフォームを使用している場合は、1の手順やその他適宜置き換えてください。
- EKSの設定
- Dockerイメージの準備
- Kubernetesの設定
EKSの設定
eksctlの準備
eksctlを最新バージョンにアップデート
$ brew upgrade eksctl && brew link --overwrite eksctl
eksctlをインストールしてない場合は以下の方法でインストール
$ brew tap weaveworks/tap
$ brew install weaveworks/tap/eksctl
$ eksctl version
0.18.0
(参照) eksctl の開始方法
VPCの準備
予め新規にVPCとプライベートサブネットを3つ作成し、プライベートサブネットのルーティングテーブルとして、0.0.0.0/0宛にNAT Gateway, VPC PeeringでRDS, ElastiCacheへのルーティングを設定します。 このプライベートサブネットはNLB配下のターゲットインスタンスを配置するためのものとなります。また、RDSやElastiCacheは異なるVPCにある既存のものを利用する前提となっています。
VPC Peeringを使用する場合は、作成するEKSクラスターのVPCを作成する際、CIDRの重複がないことなどVPC Peeringの制約に注意ください。
NLB用に各AZに計3つのパブリックサブネットを作成し、以下のタグを付与します。
- kubernetes.io/cluster/mywebsite-cluster shared
- kubernetes.io/role/elb 1
(参照) クラスター VPC に関する考慮事項
EKSクラスターの作成
以下のようにEKSクラスターを作成
$ eksctl create cluster \
--name test-cluster \
--region us-west-2 \
--version 1.15 \
--nodegroup-name mywebsite-ng \
--node-type t3.medium \
--nodes 3 \
--nodes-min 2 \
--nodes-max 4 \
--ssh-access \
--vpc-public-subnets "subnet-054211583a350c088,subnet-054211583a350c088,subnet-0864ac20958b3b37c" \
--ssh-public-key my_main_key \
--managed
作成に失敗すると、CloudFormationのスタックのロールバックに時間を要し、再度リクエストを投げられるようになるまで時間がかかります。
[✖] creating CloudFormation stack "eksctl-mywebsite-cluster-cluster": AlreadyExistsException: Stack [eksctl-mywebsite-cluster-cluster] already exists
status code: 400, request id: 411a194d-cf37-4197-ab3b-41fa9672cf80
クラスターは以下の方法で削除します。
$ eksctl delete cluster \
--name mywebsite-cluster2 \
--wait
スタックの状況はコマンドで確認できます。
$ aws cloudformation describe-stacks
以下のようにreadyの文字で作成完了していることを確認できます。
[ℹ] eksctl version 0.18.0
[ℹ] using region us-west-2
[✔] using existing VPC (vpc-036234633815de38e) and subnets (private:[] public:[subnet-054211583a350c088 subnet-0864ac20958b3b37c])
[!] custom VPC/subnets will be used; if resulting cluster doesn't function as expected, make sure to review the configuration of VPC/subnets
[ℹ] using EC2 key pair %!!(MISSING)q(*string=<nil>)
[ℹ] using Kubernetes version 1.15
[ℹ] creating EKS cluster "mywebsite-cluster" in "us-west-2" region with managed nodes
[ℹ] will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup
[ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=us-west-2 --cluster=mywebsite-cluster'
[ℹ] CloudWatch logging will not be enabled for cluster "mywebsite-cluster" in "us-west-2"
[ℹ] you can enable it with 'eksctl utils update-cluster-logging --region=us-west-2 --cluster=mywebsite-cluster'
[ℹ] Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "mywebsite-cluster" in "us-west-2"
[ℹ] 2 sequential tasks: { create cluster control plane "mywebsite-cluster", create managed nodegroup "mywebsite-ng" }
[ℹ] building cluster stack "eksctl-mywebsite-cluster-cluster"
[ℹ] deploying stack "eksctl-mywebsite-cluster-cluster"
[ℹ] building managed nodegroup stack "eksctl-mywebsite-cluster-nodegroup-mywebsite-ng"
[ℹ] deploying stack "eksctl-mywebsite-cluster-nodegroup-mywebsite-ng"
[✔] all EKS cluster resources for "mywebsite-cluster" have been created
[✔] saved kubeconfig as "/Users/hayshogo/.kube/config"
[ℹ] nodegroup "mywebsite-ng" has 3 node(s)
[ℹ] node "ip-10-0-0-151.us-west-2.compute.internal" is ready
[ℹ] node "ip-10-0-20-235.us-west-2.compute.internal" is ready
[ℹ] node "ip-10-0-20-244.us-west-2.compute.internal" is ready
[ℹ] waiting for at least 2 node(s) to become ready in "mywebsite-ng"
[ℹ] nodegroup "mywebsite-ng" has 3 node(s)
[ℹ] node "ip-10-0-0-151.us-west-2.compute.internal" is ready
[ℹ] node "ip-10-0-20-235.us-west-2.compute.internal" is ready
[ℹ] node "ip-10-0-20-244.us-west-2.compute.internal" is ready
[ℹ] kubectl command should work with "/Users/hayshogo/.kube/config", try 'kubectl get nodes'
[✔] EKS cluster "mywebsite-cluster" in "us-west-2" region is ready
NLBはServiceのリソースを作成しましたが、以下のようにエンドポイントを確認できます。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 72m
mywebsite-service LoadBalancer 172.20.203.140 a25f46cd53643416d9bb376462b33f80-02aa51afd469eb5d.elb.us-west-2.amazonaws.com 80:30759/TCP,443:31461/TCP 18m
対象のドメインとNLBのFQDNの関連付けについて、Route53を利用している場合はAliasレコード、それ以外のレジストラを利用している場合はCNAMEレコードに登録しておきます。
Dockerイメージの準備
DockerHubからTomcatのイメージを利用してDockerイメージを作成します。
$ mkdir mywebsite && cd $_
$ mkdir conf
conf/以下のTomcatの設定ファイルとしてserver.xmlを配置します。
$ conf/server.xml
server.xmlは以下の内容で記載します。
- server.xml
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="/" docBase="hayashier-website-0.0.1-SNAPSHOT" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
Dockerfileを作成します。
$ vim Dockerfile
- Dockerfile
FROM tomcat:9.0.34-jdk11
MAINTAINER "Shogo Hayashi <goodheaven700@gmail.com>"
ADD hayashier-website-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/
COPY conf/server.xml /usr/local/tomcat/conf/server.xml
EXPOSE 80
CMD ["catalina.sh", "run"]
Spring MVCなどのように作成したwarファイルをDockerイメージを作成するディレクトリにコピーしてきます。
$ cp /Path/To/MavenProject/target/hayashier-website-0.0.1-SNAPSHOT.war .
ローカルでテストする場合は以下のようにビルドしてWebサーバを稼働させておきます。
$ docker build -t mywebsite .
$ docker run -p 80:80 --rm -it mywebsite/tomcat
正常に稼働していることを確認できます。また、http://localhost でアクセスできることも確認します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e5b508c18f6 mywebsite/tomcat "catalina.sh run" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 8080/tcp nervous_khorana
$ docker exec -it 0e5b508c18f6 bash
root@0e5b508c18f6:/usr/local/tomcat#
動作に問題がない場合、ECRにレポジトリを予め作成しておき、こちらにイメージをpushします。以下はECRのコンソール上でも実行例として表示されるものとなります。
$ aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite
$ docker build -t mywebsite .
$ docker tag mywebsite:latest xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:latest
$ docker push xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:latest
Kubernetesの設定
以下の3つに分けて説明を行います。
- NLBの設定
- 機密情報の受け渡し設定
- コンテナ設定
NLBの設定
NLBを作成するため、service-nlb.yamlという名前で以下のようにマニフェストファイルを作成します。 ここではNLBのTLSリスナーを作成するために、事前に対象のドメインでSSL証明書をACMで発行済みであることを前提としています。
- service-nlb.yaml
apiVersion: v1
kind: Service
metadata:
name: mywebsite-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http"
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
spec:
type: LoadBalancer
selector:
app: mywebsite
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 80
機密情報の受け渡し設定
EKSでは現状ECSのようにSecret Managerに対応しておらず、アプリケーション上からSDKを通してしか利用することができません。
[EKS] [request]: AWS Secrets Manager / SSM Parameter Store #168
そのため、Kubernetesで稼働するアプリケーションに機密情報を渡すために、KubernetesのSecretリソースを利用します。
KubernetesのSecretの機能では、YAMLファイルを作成して、kubectl apply
コマンドを使用する方法と、kubectl create secret generic <Secretリソース名>
で直接コマンドで直接作成する方法があります。
YAMLファイルを通してSecretのリソースを利用する場合、環境変数のキーおよび値をBase64でエンコーディングしておく必要があります。
$ echo -n 'jdbc:mysql://xxxxxxxxxx.yyyyyyyyyy.us-west-2.rds.amazonaws.com:3306/mywebsite' | base64
amRiYzpteXNxbDovL3h4eHh4eHh4eHgueXl5eXl5eXl5eS51cy13ZXN0LTIucmRzLmFtYXpvbmF3cy5jb206MzMwNi9teXdlYnNpdGU=
$ echo -n 'sampleuser' | base64
c2FtcGxldXNlcg==
$ echo -n 'Test1234' | base64
VGVzdDEyMzQ=
$ echo -n 'zzzzzzzzzz.aaaaaa.ng.0001.usw2.cache.amazonaws.com' | base64
enp6enp6enp6ei5hYWFhYWEubmcuMDAwMS51c3cyLmNhY2hlLmFtYXpvbmF3cy5jb20=
エンコーディングした値をSecretリソースのマニフェストファイルで指定します。secret-mywebsite.yamlというような名前でファイルを作成します。
- secret-mywebsite.yaml
apiVersion: v1
kind: Secret
metadata:
name: mywebsite-secret
data:
dbhost: amRiYzpteXNxbDovL3h4eHh4eHh4eHgueXl5eXl5eXl5eS51cy13ZXN0LTIucmRzLmFtYXpvbmF3cy5jb206MzMwNi9teXdlYnNpdGU=
dbuser: c2FtcGxldXNlcg==
dbpassword: VGVzdDEyMzQ=
cachehost: enp6enp6enp6ei5hYWFhYWEubmcuMDAwMS51c3cyLmNhY2hlLmFtYXpvbmF3cy5jb20=
kubectl apply
コマンドで適用します。
$ kubectl apply -f secret-mywebsite.yaml
secret/mywebsite-secret created
もしくは、YAMLファイルを使用せずに、kubectl create secret generic <Secretリソース名>
で直接コマンドで行うこともできます。YAMLファイルを使用する際は、事前にBase64でエンコーディングする必要はありません。
$ kubectl create secret generic mywebsite-secret \
--from-literal=dbhost='jdbc:mysql://xxxxxxxxxx.yyyyyyyyyy.us-west-2.rds.amazonaws.com:3306/mywebsite' \
--from-literal=dbuser='sampleuser' \
--from-literal=dbpassword='Test1234' \
--from-literal=cachehost='zzzzzzzzzz.aaaaaa.ng.0001.usw2.cache.amazonaws.com'
Spring MVCの方でMySQLやRedisの設定で.propertiesファイルに設定を記載している場合、以下のように環境変数で取得した値を代入するように設定します。
- db.properties
db.url=${DBHOST}
db.username=${DBUSER}
db.password=${DBPASSWORD}
- cache.properties
cache.host=${CACHEHOST}
cache.port=6379
cache.password=
cache.timeout=
後述するようにPod設定部分に以下のように設定することでコンテナで稼働するアプリケーションに環境変数を渡します。env直下のnameで環境変数名、secretKeyRef直下のnameでSecretリソースのmetadata.nameで指定した名前、keyでSecretリソースのdata以下で指定したキーを指定します。
env:
- name: DBHOST
valueFrom:
secretKeyRef:
name: mywebsite-secret
key: dbhost
- Reference
コンテナ設定
Deploymentを通して起動する方法がKubernetesで推奨されている方法となります。そのため、ここではDeploymentリソースにより、ReplicaSetを作成し、目的のPodを立ち上げるという3層構成でコンテナを立ち上げます。
deployment-mywebiste.yamlという名前でDeploymentリソースのマニフェストファイルを作成します。spec以下でReplicaSetリソースの定義を行います。ReplicaSetリソース以下のspec以下でPodの定義を行います。
Pod定義以下のenvで、先程KubernetesのSecretリソースで作成した環境変数の設定を行っています。
resourcesでリソース制限を行っています。デフォルトではCPUとメモリーの制限のみが可能ですが、Device Pluginによりその他GPUなどのリソースも制限可能になります。
- deployment-mywebiste.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-mywebsite
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 3
replicas: 3
selector:
matchLabels:
app: mywebsite
template:
metadata:
labels:
app: mywebsite
spec:
containers:
- name: mywebsite-container
image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1
ports:
- containerPort: 80
env:
- name: DBHOST
valueFrom:
secretKeyRef:
name: mywebsite-secret
key: dbhost
- name: DBUSER
valueFrom:
secretKeyRef:
name: mywebsite-secret
key: dbuser
- name: DBPASSWORD
valueFrom:
secretKeyRef:
name: mywebsite-secret
key: dbpassword
- name: CACHEHOST
valueFrom:
secretKeyRef:
name: mywebsite-secret
key: cachehost
resources:
requests:
memory: 512Mi
cpu: 250m
limits:
memory: 4096Mi
cpu: 1000m
kubectl apply
コマンドで適用します。
$ kubectl apply -f deployment-mywebsite.yaml
deployment.apps/deployment-mywebsite created
以下のように作成したDeploymentリソースの詳細を確認できます。
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-mywebsite 3/3 3 3 79m
kubectl describe deployment.apps/<Deployment name>
コマンドで詳細を確認できます。
$ kubectl describe deployment.apps/deployment-mywebsite
Name: deployment-mywebsite
Namespace: default
CreationTimestamp: Wed, 06 May 2020 23:44:45 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=mywebsite
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 0 max unavailable, 3 max surge
Pod Template:
Labels: app=mywebsite
Containers:
mywebsite-container:
Image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 1
memory: 4Gi
Requests:
cpu: 250m
memory: 512Mi
Environment:
DBHOST: <set to the key 'dbhost' in secret 'mywebsite-secret'> Optional: false
DBUSER: <set to the key 'dbuser' in secret 'mywebsite-secret'> Optional: false
DBPASSWORD: <set to the key 'dbpassword' in secret 'mywebsite-secret'> Optional: false
CACHEHOST: <set to the key 'cachehost' in secret 'mywebsite-secret'> Optional: false
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: deployment-mywebsite-68b6fbcd95 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 13m deployment-controller Scaled up replica set deployment-mywebsite-68b6fbcd95 to 3
起動したPodの詳細を確認できます。
$ kubectl describe pod/deployment-mywebsite-68b6fbcd95-bvjr9
Name: deployment-mywebsite-68b6fbcd95-bvjr9
Namespace: default
Priority: 0
Node: ip-10-0-20-7.us-west-2.compute.internal/10.0.20.7
Start Time: Wed, 06 May 2020 23:44:45 +0900
Labels: app=mywebsite
pod-template-hash=68b6fbcd95
Annotations: kubernetes.io/psp: eks.privileged
Status: Running
IP: 10.0.20.11
IPs: <none>
Controlled By: ReplicaSet/deployment-mywebsite-68b6fbcd95
Containers:
mywebsite-container:
Container ID: docker://9ca22af04a231902b5e5e20377a3669aec9e6e617288e31fe99eca2ce032c648
Image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1
Image ID: docker-pullable://xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite@sha256:54fbaaab81098aa99456fb4d4bedfc468f90d4398eabeec55ae1e86bdc01cd71
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 06 May 2020 23:44:48 +0900
Ready: True
Restart Count: 0
Limits:
cpu: 1
memory: 4Gi
Requests:
cpu: 250m
memory: 512Mi
Environment:
DBHOST: <set to the key 'dbhost' in secret 'mywebsite-secret'> Optional: false
DBUSER: <set to the key 'dbuser' in secret 'mywebsite-secret'> Optional: false
DBPASSWORD: <set to the key 'dbpassword' in secret 'mywebsite-secret'> Optional: false
CACHEHOST: <set to the key 'cachehost' in secret 'mywebsite-secret'> Optional: false
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5cr55 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-5cr55:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-5cr55
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 13m default-scheduler Successfully assigned default/deployment-mywebsite-68b6fbcd95-bvjr9 to ip-10-0-20-7.us-west-2.compute.internal
Normal Pulling 13m kubelet, ip-10-0-20-7.us-west-2.compute.internal Pulling image "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1"
Normal Pulled 13m kubelet, ip-10-0-20-7.us-west-2.compute.internal Successfully pulled image "xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1"
Normal Created 13m kubelet, ip-10-0-20-7.us-west-2.compute.internal Created container mywebsite-container
Normal Started 13m kubelet, ip-10-0-20-7.us-west-2.compute.internal Started container mywebsite-container
作成したリソースの種類全体は以下のように確認できます。-Aオプションでnamespace全体を表示、-o wideオプションでより詳細に情報を表示します。
$ kubectl get all -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default pod/deployment-mywebsite-68b6fbcd95-bvjr9 1/1 Running 0 11h 10.0.20.11 ip-10-0-20-7.us-west-2.compute.internal <none> <none>
default pod/deployment-mywebsite-68b6fbcd95-dbp8q 1/1 Running 0 11h 10.0.20.153 ip-10-0-20-227.us-west-2.compute.internal <none> <none>
default pod/deployment-mywebsite-68b6fbcd95-fkjp8 1/1 Running 0 11h 10.0.0.234 ip-10-0-0-246.us-west-2.compute.internal <none> <none>
kube-system pod/aws-node-28mxf 1/1 Running 0 13h 10.0.0.246 ip-10-0-0-246.us-west-2.compute.internal <none> <none>
kube-system pod/aws-node-55jpq 1/1 Running 0 13h 10.0.20.7 ip-10-0-20-7.us-west-2.compute.internal <none> <none>
kube-system pod/aws-node-94qdr 1/1 Running 0 13h 10.0.20.227 ip-10-0-20-227.us-west-2.compute.internal <none> <none>
kube-system pod/coredns-86d5cbb4bd-nzx5h 1/1 Running 0 13h 10.0.20.133 ip-10-0-20-7.us-west-2.compute.internal <none> <none>
kube-system pod/coredns-86d5cbb4bd-xzkpk 1/1 Running 0 13h 10.0.20.159 ip-10-0-20-227.us-west-2.compute.internal <none> <none>
kube-system pod/kube-proxy-jdsms 1/1 Running 0 13h 10.0.0.246 ip-10-0-0-246.us-west-2.compute.internal <none> <none>
kube-system pod/kube-proxy-qj4vq 1/1 Running 0 13h 10.0.20.7 ip-10-0-20-7.us-west-2.compute.internal <none> <none>
kube-system pod/kube-proxy-qqtxg 1/1 Running 0 13h 10.0.20.227 ip-10-0-20-227.us-west-2.compute.internal <none> <none>
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
default service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 4d16h <none>
default service/mywebsite-service LoadBalancer 172.20.203.140 a25f46cd53643416d9bb376462b33f80-02aa51afd469eb5d.elb.us-west-2.amazonaws.com 80:30759/TCP,443:31461/TCP 4d15h app=mywebsite
kube-system service/kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP 4d16h k8s-app=kube-dns
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
kube-system daemonset.apps/aws-node 3 3 3 3 3 <none> 4d16h aws-node 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.5.7 k8s-app=aws-node
kube-system daemonset.apps/kube-proxy 3 3 3 3 3 <none> 4d16h kube-proxy 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/kube-proxy:v1.15.11 k8s-app=kube-proxy
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
default deployment.apps/deployment-mywebsite 3/3 3 3 11h mywebsite-container xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1 app=mywebsite
kube-system deployment.apps/coredns 2/2 2 2 4d16h coredns 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.6.6 eks.amazonaws.com/component=coredns,k8s-app=kube-dns
NAMESPACE NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
default replicaset.apps/deployment-mywebsite-68b6fbcd95 3 3 3 11h mywebsite-container xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1 app=mywebsite,pod-template-hash=68b6fbcd95
kube-system replicaset.apps/coredns-86d5cbb4bd 2 2 2 4d16h coredns 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.6.6 eks.amazonaws.com/component=coredns,k8s-app=kube-dns,pod-template-hash=86d5cbb4bd
Error
[✖] AWS::EKS::Nodegroup/ManagedNodeGroup: CREATE_FAILED – "Nodegroup mywebsite-ng failed to stabilize: Internal Failure"
eksctl create cluster
コマンドで上記のエラー。このCloudFormationからのエラーはサブネットのルーティングの設定が意図したものになっていなかった。
ModuleNotFoundError: No module named 'pip._internal.cli.main'
pipコマンドで何打っても上記エラーになる。pipの再インストールで解消。
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python3 get-pip.py --force-reinstall
aws: error: argument operation: Invalid choice, valid choices are:
ECRで例示されたプッシュコマンドを打つと以下のエラー
$ aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:
aws help
aws <command> help
aws <command> <subcommand> help
aws: error: argument operation: Invalid choice, valid choices are:
AWS CLI 1.7.10およびv2で使用できる
- https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html#cliv2-migration-ecr-get-login
The aws ecr get-login-password command is available in the AWS CLI version 1.17.10 and later, and the AWS CLI version 2.
v2をインストール
$ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
$ sudo installer -pkg AWSCLIV2.pkg -target /
インストールが完了したことを確認
$ aws --version
aws-cli/2.0.10 Python/3.7.4 Darwin/18.7.0 botocore/2.0.0dev14
Installing the AWS CLI version 2 on macOS
Error syncing load balancer: failed to ensure load balancer: could not find any suitable subnets for creating the ELB
kubectl apply
コマンドでNLB作成後、kubectl describe service
コマンドでイベントを確認すると上記エラー
$ kubectl describe service mywebsite-service
Name: mywebsite-service
Namespace: default
Labels: <none>
Annotations: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
service.beta.kubernetes.io/aws-load-balancer-type: nlb
Selector: app=mywebsite
Type: LoadBalancer
IP: 172.20.246.65
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 30251/TCP
Endpoints: 10.0.0.163:80,10.0.20.48:80,10.0.20.80:80
Port: https 443/TCP
TargetPort: 80/TCP
NodePort: https 30417/TCP
Endpoints: 10.0.0.163:80,10.0.20.48:80,10.0.20.80:80
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal EnsuringLoadBalancer 4m52s (x9 over 20m) service-controller Ensuring load balancer
Warning SyncLoadBalancerFailed 4m52s (x9 over 20m) service-controller Error syncing load balancer: failed to ensure load balancer: could not find any suitable subnets for creating the ELB
ドキュメントに従って、NLB用のパブリックサブネットを作成し、以下のタグを付与
- kubernetes.io/cluster/mywebsite-cluster shared
- kubernetes.io/role/elb 1
解消される
$ kubectl describe service mywebsite-service
Name: mywebsite-service
Namespace: default
Labels: <none>
Annotations: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
service.beta.kubernetes.io/aws-load-balancer-type: nlb
Selector: app=mywebsite
Type: LoadBalancer
IP: 172.20.203.140
LoadBalancer Ingress: a25f46cd53643416d9bb376462b33f80-02aa51afd469eb5d.elb.us-west-2.amazonaws.com
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 30759/TCP
Endpoints: 10.0.0.163:80,10.0.20.48:80,10.0.20.80:80
Port: https 443/TCP
TargetPort: 80/TCP
NodePort: https 31461/TCP
Endpoints: 10.0.0.163:80,10.0.20.48:80,10.0.20.80:80
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning SyncLoadBalancerFailed 15m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating listener: "Error creating load balancer listener: \"CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\\n\\tstatus code: 400, request id: 6127c721-d11b-4108-b7aa-74c3590ebb2d\""
Warning SyncLoadBalancerFailed 14m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: 5f977567-1152-4cb3-8cb7-b37a915894e3"
Warning SyncLoadBalancerFailed 14m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: dab8610c-de7e-451e-8e1a-97ff40c4df0a"
Warning SyncLoadBalancerFailed 14m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: e3f49179-a9a2-4f83-9046-1495e97d4e6a"
Warning SyncLoadBalancerFailed 13m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: a6c1e5ea-e8a3-49ba-a3ef-b082cc7dc6a2"
Warning SyncLoadBalancerFailed 12m service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: 19785156-a185-4cbe-96e9-e3bda36f6686"
Warning SyncLoadBalancerFailed 9m42s service-controller Error syncing load balancer: failed to ensure load balancer: Error creating load balancer listener: "CertificateNotFound: Certificate 'arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d' not found\n\tstatus code: 400, request id: b0d6355c-cd9f-47fc-89d9-92f26f40995c"
Normal EnsuringLoadBalancer 4m42s (x8 over 15m) service-controller Ensuring load balancer
Normal EnsuredLoadBalancer 4m40s service-controller Ensured load balancer
The connection to the server kubernetes.docker.internal:6443 was refused - did you specify the right host or port?
Docker for Macで稼働しているローカル環境のKubernetesのクラスターに対してkubectlコマンドを実行すると上記エラー。Kubernetesクラスターを起動して解消
<!--
rpc error: code = Unknown desc = Error response from daemon: pull access denied for mywebsite, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
$ docker login
Authenticating with existing credentials...
Login Succeeded
-->
E: Unable to locate package telnet
Dockerイメージからコンテナを稼働後、シェル環境にアクセスしてもtelnetをインストールできない。
root@0e5b508c18f6:/usr/local/tomcat# apt-get install telnet
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package telnet
apt-get update
コマンドを一度実行すれば良い
Request processing failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
$ ip addr show en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 18:65:90:cd:c3:ab
inet 192.168.11.6/24 brd 192.168.11.255 en0
$ sudo ip address add 192.168.11.6/24 dev lo0
Password:
Executing: /usr/bin/sudo /sbin/ifconfig lo0 add 192.168.11.6/24
$ ip addr show lo0
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1/8 lo0
inet6 ::1/128
inet6 fe80::1/64 scopeid 0x1
inet 192.168.11.6/24 lo0
Springの接続先を上のIPアドレスに置き換え
ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.11.6' (61)
- bind-addressによる制限を解除
$ mysqld --help --verbose | grep my.cnf
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf
my.cnf, $MYSQL_TCP_PORT, /etc/services, built-in default
/usr/local/etc/my.cnf
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
# bind-address = 127.0.0.1
- 権限テーブルでリモートからのアクセスを許可
mysql> create user 'root'@'%' identified by 'Test1234';
Query OK, 0 rows affected (0.01 sec)
mysql> select user , host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| root | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)
mysql> drop user root@localhost;
Query OK, 0 rows affected (0.01 sec)
mysql> select user , host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| root | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
+------------------+-----------+
4 rows in set (0.00 sec)
$ mysql -h 192.168.11.6 -uroot -p
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.19 Homebrew
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
RDSだと以下のようになっているのでこちらの作業は不要
mysql> select user , host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| hayashier | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| rdsadmin | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)
権限テーブルの設定ミスでログインできなくなった場合
以下のようなエラーでログインできなくなった場合
$ mysql -uroot -p
Enter password:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
以下のコマンドを起動
$ mysqld_safe --skip-grant-tables
2020-05-01T01:13:38.6NZ mysqld_safe Logging to '/usr/local/var/mysql/186590cdc3ab.ant.amazon.com.err'.
2020-05-01T01:13:38.6NZ mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql
--skip-grant-tablesオプションによる起動中は、以下のようなコマンドが使用できなくなる
mysql> CREATE USER 'root'@'localhost' IDENTIFIED BY 'Test1234';
ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement
以下の方法で回避して、権限テーブルを設定
mysql> CREATE TEMPORARY TABLE mysql.tmpUser SELECT * FROM mysql.user WHERE host="%" and user="root";
mysql> UPDATE mysql.tmpUser SET host="localhost" WHERE user = "root";
mysql> INSERT INTO mysql.user SELECT * FROM mysql.tmpUser;
mysql> drop user root@'%';
(参照) How to get all privileges back to the root user in MySQL?