在Amazon EKS上运行Rails API应用程序
大致内容
我使用备受瞩目的Amazon EKS在街上运行了一个Rails应用程序。它就像是教程内容的加强版。
EKS 是什么?
目前在AWS上提供的托管式Kubernetes服务。
以下地区可用(截至2018年06月18日)。
-
- 米国西部 (オレゴン) (us-west-2)
- 米国東部 (バージニア北部) (us-east-1)
载入应用程序。
-
- Rails : 5.2.0
-
- Ruby : 2.5.1
- DB : PostgreSQL
这次,我们使用了RDS作为数据库。
然而,使用名为存储类的东西可以在Kubernetes上准备存储。
使用它可以运行需要持久化的服务,如数据库。
需要的东西 de
-
- バージョン1.15.32以降のAWSCLI
Amazon EKSを触るのに必要
brew版は 1.15.32以降 の要件が満たせず、pipで再度インストールした(2018.06.18現在)
kubectl
Kubernetesクラスタに対してコマンドを実行するためのCLI
Homebrewでインストールした
heptio-authenticator-aws
IAMの情報を使ってKubernetesクラスタへの認証を行うためのツール
go get でgithubからインストールした
创建资源
借鉴了基本结构
我参考了这个cfn.yml文件,它是从https://github.com/y13i/aws-eks-example中拷贝过来的。
我借用了cfn.yml文件,并进行了自定义后使用。
非常感谢您的帮助和支持。非常感谢。
这个文件使用一个CloudFormation堆栈来创建EKS所需的所有资源,并且还将网络配置规划成特定的形式。
大致如此。
-
- VPC
パブリックサブネット*2
プライベートサブネット*2
プライベートサブネット内にアプリ用のインスタンス設置
EKSクラスタの作成
定制化的部分
为了运行Rails应用程序,还需要以下内容,因此在yaml文件中进行了追加。
-
- RDS
プライベートサブネット内に設置
ECRのリポジトリ作成
S3の設定
参数: 添加部分
DBUsername:
Type: String
DBPassword:
Type: String
NoEcho: true
资源:附加的部分
VPCEndpointForS3:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- Ref: PublicRouteTable
- Ref: PrivateRouteTable0
- Ref: PrivateRouteTable1
VpcId:
Ref: Vpc
ServiceName:
Fn::Join:
- "."
- - com
- amazonaws
- Ref: AWS::Region
- s3
DBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription:
Ref: AWS::StackName
SubnetIds:
- Ref: PrivateSubnet0
- Ref: PrivateSubnet1
Tags:
- Key: Name
Value:
Ref: AWS::StackName
DBParameterGroup:
Type: AWS::RDS::DBParameterGroup
Properties:
Family: postgres9.6
Description:
Ref: AWS::StackName
Parameters:
client_encoding: UTF8
timezone: Asia/Tokyo
DBInstance:
Type: "AWS::RDS::DBInstance"
Properties:
AllocatedStorage: 20
DBInstanceClass: db.t2.micro
DBName:
Ref: AWS::StackName
DBParameterGroupName:
Ref: DBParameterGroup
DBSubnetGroupName:
Ref: DBSubnetGroup
Engine: postgres
EngineVersion: "9.6.6"
MasterUsername:
Ref: DBUsername
MasterUserPassword:
Ref: DBPassword
MultiAZ: true
PubliclyAccessible: false
StorageType: gp2
Tags:
- Key: Name
Value:
Ref: AWS::StackName
VPCSecurityGroups:
- Fn::GetAtt:
- DBSecurityGroup
- GroupId
DBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for rds
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId:
Fn::GetAtt:
- NodeSecurityGroup
- GroupId
VpcId:
Ref: Vpc
Tags:
- Key: Name
Value:
Ref: AWS::StackName
ContainerRepository:
Type: AWS::ECR::Repository
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 365
LogGroupName:
Ref: AWS::StackName
StorageBucket:
Type: AWS::S3::Bucket
StorageUser:
Type: AWS::IAM::User
Properties:
ManagedPolicyArns:
- Ref: StorageUserPolicy
StorageAccessKey:
Type: AWS::IAM::AccessKey
Properties:
UserName:
Ref: StorageUser
StorageUserPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: s3:*
Resource:
- Fn::GetAtt:
- StorageBucket
- Arn
- Fn::Join:
- ""
- - Fn::GetAtt:
- StorageBucket
- Arn
- /*
-
输出:新增的部分
ContainerRepository:
Value:
Ref: ContainerRepository
DBHostName:
Value:
Fn::GetAtt:
- DBInstance
- Endpoint.Address
DBPort:
Value:
Fn::GetAtt:
- DBInstance
- Endpoint.Port
由于准备就绪,现在可以部署了。
目录结构大致如下。
api/
├ app/
├ config/
│ .
│ .
│ .
├ infra/
│ └ cfn.yml
└ Dockerfile
API/
├ 应用程序/
├ 配置/
│ .
│ .
│ .
├ 基础设施/
│ └ cfn.yml
└ Docker文件
在api目录下执行命令
※大约需要15到20分钟才能完成
$ aws cloudformation deploy --template-file infra/cfn.yml --capabilities CAPABILITY_IAM --stack-name development --parameter-overrides DBUsername=app DBPassword=hogehoge
一旦部署完成后,从管理控制台中选择CloudFormation > 堆栈 > [输出]选项卡,然后查看输出结果。
为了访问EKS集群,需要配置身份验证相关的设置。
创建.kube/
$ mkdir -p .kube/
创建 kubeconfig 文件
$ touch ./.kube/k8s-config.yml
apiVersion: v1
clusters:
- cluster:
server: <CFnで出力された EKSClusterEndpoint>
certificate-authority-data: <CFnで出力された EKSClusterCertificateAuthorityData>
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: aws
name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
command: heptio-authenticator-aws
args:
- "token"
- "-i"
- <CFnで出力された EKSClusterName>
设置环境变量KUBECONFIG
在执行kubectl命令时,添加路径以引用k8s-config.yml文件。
在direnv中追加或在.bash_profile中追加。
export KUBECONFIG=<k8s-config.ymlへのパス>
试着访问集群
$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP xxx.xx.x.x <none> 443/TCP 8m
※ 指令:如果在heptio-authenticator-aws相关的地方出现错误,请将k8s-config.yml文件中的路径替换为指向heptio-authenticator-aws的相对路径。
例)../../../go/bin/heptio-authenticator-aws 可以在中国本地化吗?我只需要一种选项。
工作节点的设置
准备一个用于存放Kubernetes配置文件的位置
$ mkdir ./kubernetes/
创建配置文件
$ touch kubernetes/aws-auth-configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: <CFnで出力された NodeInstanceRole>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
让节点加入到集群中
$ kubectl apply -f kubernetes/aws-auth-configmap.yml
configmap "aws-auth" created
获取并确认节点列表。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-XX-X-XX-XXX.ec2.internal Ready <none> 1m v1.10.3
ip-XX-X-XX-XX.ec2.internal Ready <none> 51s v1.10.3
如果STATUS不是Ready,就会一直温柔地等待它变成Ready。
$ kubectl get nodes --watch
设置环境变量
无论是使用direnv还是.bash_profile都可以,随你喜欢。
export AWS_ACCOUNT_ID=xxxxx
export AWS_DEFAULT_REGION=us-east-1
export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=xxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxx
export CONTAINER_REPOSITORY=<CFnで出力された ContainerRepository>
export CONTAINER_IMAGE_TAG=<適当なタグ>
登录ECR,构建镜像,打标签,推送。
$ $(aws ecr get-login --no-include-email)
$ docker build -t "$CONTAINER_REPOSITORY:$CONTAINER_IMAGE_TAG" .
$ docker tag "$CONTAINER_REPOSITORY:$CONTAINER_IMAGE_TAG" "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$CONTAINER_REPOSITORY:$CONTAINER_IMAGE_TAG"
$ docker push "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$CONTAINER_REPOSITORY:$CONTAINER_IMAGE_TAG"
创建 Kubernetes 清单文件
创建秘密
为了使用环境变量,我在Pod中准备了它。
$ touch kubernetes/eks-secret.yml
apiVersion: v1
kind: Secret
metadata:
name: eks-secret
type: Opaque
data:
HOGE: aG9nZQ==
数据是由键值对组成,值是经过base64编码的值。
我正在复制并粘贴通过命令生成的内容。
$ echo -n "hoge" | base64
aG9nZQ==
在这种情况下,Pod能够使用值为hoge的环境变量HOGE。
将创建的清单应用于集群。
$ kubectl create -f kubernetes/eks-secret.yml
创建部署
Pod和ReplicaSets的配置被整合在一起。
$ touch kubernetes/eks-deployment.yml
提前获取ECR的镜像信息
$ echo "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$CONTAINER_REPOSITORY:$CONTAINER_IMAGE_TAG"
xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx
将获取到的图像信息放入image中。
使用 AWS EC2 容器注册表时,需要完整指定从 URL 到标签的部分。
apiVersion: apps/v1
kind: Deployment
metadata:
name: eks-deployment
spec:
replicas: 3
selector:
matchLabels:
app: rails-api
template:
metadata:
labels:
app: rails-api
spec:
containers:
- name: rails-api
image: xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: eks-secret
args:
- rails
- server
- -p
- '3000'
- -b
- '0.0.0.0'
这个句子的意思是以下这样的。
xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx イメージをもとにしたコンテナが入ったPodを作る。
そのPodにラベル app=rails-api を付与する。
ラベル app=rails-api がついたPodが3つになるようレプリケーションする。
Podは外部通信用に3000ポートを開ける。
コンテナ作成時に rails server -p ‘3000’ -b ‘0.0.0.0’ を実行する。
将创建的清单应用于集群。
$ kubectl create -f kubernetes/eks-deployment.yml
创建服务
放置Pod可以运行应用程序是一件好事,但是要如何访问该应用程序呢?解决这个问题的是服务。
需要这个来处理用户的请求。
$ touch kubernetes/eks-service.yml
kind: Service
apiVersion: v1
metadata:
name: eks-service
spec:
type: LoadBalancer
selector:
app: rails-api
ports:
- protocol: TCP
port: 80
targetPort: 3000
这句话的意思如下。
- 80ポートへアクセスがあったとき、ラベルが app=rails-api のPodの3000ポートにつなぐ
将创建的清单应用到集群上。
$ kubectl create -f kubernetes/eks-service.yml
创建工作
不是像应用程序一样需要始终运行的东西,而是希望执行后消失的东西,可以使用“任务”。
比如在Rails的案例中,我认为像rails db:create或者rails db:migrate这样的命令只需要执行一次。
为此,我准备了一份工作。
$ touch kubernetes/eks-create-job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: eks-create-job
spec:
backoffLimit: 3
parallelism: 1
completions: 1
template:
spec:
containers:
- name: rails-create
image: xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: eks-secret
args:
- rails
- db:create
restartPolicy: Never
Pod的组件与deployment相同,唯一不同的是arg(=执行的命令)。
从意思上来说
xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx イメージをもとにしたコンテナが入ったPodを作る。
Podは外部通信用に3000ポートを開ける。
コンテナ作成時に rails db:create を実行する。
実行が失敗したら3回までリトライする。
Podは最大1つ実行する。
1つのPodの処理が成功したらjobの成功とする。
コンテナの再起動は行わない。
将制作的清单应用于集群中。
$ kubectl create -f kubernetes/eks-create-job.yml
迁移也是相同的情况。
$ touch kubernetes/eks-migrate-job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: eks-migrate-job
spec:
backoffLimit: 3
parallelism: 1
completions: 1
template:
spec:
containers:
- name: rails-migrate
image: xxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxx:xxxxx
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: eks-secret
args:
- rails
- db:migrate
restartPolicy: Never
将已创建的清单应用于集群。
$ kubectl create -f kubernetes/eks-migrate-job.yml
访问应用程序
一旦创建了服务,EKS会自动创建负载均衡器。
我想要访问那里,所以为了确认,我会执行以下命令。
$ kubectl describe services
从中找到以下项目。
LoadBalancer Ingress: xxxxxxxxxx.us-east-1.elb.amazonaws.com
xxxxxxxxxx.us-east-1.elb.amazonaws.com成为终端点。
可以通过浏览器或Postman等工具进行访问。
请提供一个参考网址。
使用Amazon弹性容器服务(Amazon Elastic Container Service)为Kubernetes部署一个Kubernetes应用程序。