はじめに
業務では普段Javaの独自フレームワークやSVN、Db2といったレガシー&ニッチな技術スタックで開発をしているため、新しい技術を自分で追っかけていたりするのですが、今回初めて使ってみたい技術を詰め込んで Web アプリを作ってみました。
記事を書くことにも不慣れなため、お見苦しい部分が多々あるかと思いますが、間違い等あればコメントいただけると泣いて喜びます。
使用した技術
言語
- バックエンド(Go, Gin-Gonic)
- フロントエンド(Nuxt.js)
インフラ
- AWS(VPC, Route53, ALB, ACM, EKS, S3, CloudFront, CloudWatch)
- コンテナ(Docker, docker-compose)
- データベース(MySQL)
- Kubernetes
- Terraform
- CI/CD(GitHub Actions)
ソースコードはこちら
※詳細は README.md にも載せています
アーキテクチャ図
ポイント解説
Terraform
初めはネットの記事をコピペして見様見真似で動かしていましたが、やはりちゃんと理解していないと問題が発生したときにドン詰まる。。
まずは、プロバイダーを定義する main.tf ファイルを用意します。
この場合、terraform の 0.12.9 バージョンを使用することになります。
「=」を「>=」にするとそのバージョン以上という意味になる。
※Terraform 0.12から構文が変わっているとのことなので、調査する時もバージョンをチェックすることを忘れないで。
terraform {
required_version = "= 0.12.9"
}
awsのバージョンやリージョンはこちらのprovider.tfで定義しています。
provider "aws" {
version = "3.0"
region = var.region
profile = var.aws_profile
}
provider "local" {
version = "2.0.0"
}
provider "tls" {
version = "3.0.0"
}
次に変数を定義する variables.tf を用意します。
よく使う値は変数にいれてここで定義しました。
AWS のクレデンシャル情報は直接記述せずに、~/.aws/credentials に定義してそれを参照するようにしました。
variable "region" {
default = "us-east-1"
}
variable "aws_profile" {
type = string
description = "AWSのプロファイル名"
default = "terraform-eks"
}
variable "project" {
default = "eks"
}
variable "environment" {
default = "dev"
}
variable "vpc_cidr_block" {
default = "10.0.0.0/16"
}
variable "num_subnets" {
default = 3
}
variable "key_name" {
type = "string"
default = "ambitious_key"
}
locals {
base_tags = {
Project = var.project
Terraform = "true"
Environment = var.environment
}
default_tags = merge(local.base_tags, map("kubernetes.io/cluster/${local.cluster_name}", "shared"))
base_name = "${var.project}-${var.environment}"
cluster_name = "${local.base_name}-amb-cluster"
cluster_version = "1.18"
public_key_file = "./${var.key_name}.id_rsa.pub"
private_key_file = "./${var.key_name}.id_rsa"
}
各AWSのリソースごとにtfファイルを定義します。
eksの場合は、kubeconfigとconfigmapをアウトプットするためにlocalに格納します。
locals {
kubeconfig = <<KUBECONFIG
apiVersion: v1
clusters:
- cluster:
server: ${aws_eks_cluster.eks-cluster.endpoint}
certificate-authority-data: ${aws_eks_cluster.eks-cluster.certificate_authority.0.data}
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: aws-iam-authenticator
args:
- "token"
- "-i"
- "${local.cluster_name}"
KUBECONFIG
eks_configmap = <<CONFIGMAPAWSAUTH
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: ${aws_iam_role.eks-node-role.arn}
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
CONFIGMAPAWSAUTH
}
resource "aws_eks_cluster" "eks-cluster" {
name = local.cluster_name
role_arn = aws_iam_role.eks-master-role.arn
version = local.cluster_version
vpc_config {
security_group_ids = [aws_security_group.cluster-master.id]
subnet_ids = aws_subnet.subnet.*.id
endpoint_public_access = true
}
depends_on = [
aws_iam_role_policy_attachment.eks-cluster-policy,
aws_iam_role_policy_attachment.eks-service-policy,
]
}
resource "aws_eks_node_group" "eks-cluster-node-group" {
cluster_name = aws_eks_cluster.eks-cluster.name
node_group_name = "eks-cluster-node-group"
node_role_arn = aws_iam_role.eks-node-role.arn
subnet_ids = aws_subnet.subnet.*.id
scaling_config {
desired_size = 1
max_size = 1
min_size = 1
}
}
リソースファイルを全て定義し終えたら、デプロイします。
terraform plan
terraform apply
apply に成功したら terraform output の結果をそれぞれファイルに保存します。
EKS ConfigMap → manifests/config_map.yml
kubectl config → .kube/config
export KUBECONFIG='.kube/config'
kubectl apply -f manifests/config_map.yml
ノードがReadyになって居ることを確認する。
kubectl get nodes
まとめ
現在の会社では、Azureを使用するプロジェクトが多いため、どのクラウドでも同じように使えるTerraformを採用しました。
実装している時はトライアンドエラーで進めていましたが、applyとdestroyには結構時間がかかるため、必要な部分だけ動作をテストするみたいなことが上手くできればよかったなぁと、振り返って思いました。もう少し勉強は必要ですが、実務でも今後導入していく予定です。
残りのGo,AWS,Nuxt.jsについては、後々別記事に書きます。
参考
実装時はこちらの記事を参考にさせていただきました。
Terraform
5分で分かるTerraform(Infrastructure as Code)
Managed Node Groupsを用いてTerraformでEKSクラスタをシュッと構築する