Microservicesにジョインするには知らない技術が多すぎたので一通り触ってみた話
Microservicesにジョインするには知らない技術が多すぎたので一通り触ってみた話:
Mercari Advent Calendar 2018 の2日目はCrossUXチームの@mkazutaka(twitterは@makazutaka)がお送りします。
昨日のアドベントカレンダーに@stanakaさんが取り上げているようにメルカリではMicroservices化に向けて開発が進んでおります。その流れに乗るように前QまでPHPを使って開発していた自分も今QからMicroservicesで実現されているサービスでの開発を行っております。
tech.mercari.com
メルカリではMicroservicesの実現にあたってGoogleCloudPlatform(GCP)、Terraform、Docker、Kubernetes、Halyard、gRPC、Goといったさまざまなサービスからフレームワーク、言語を利用しています。
メルカリでのMicroservices上での開発をする以上、これらに対して多少なりとも理解が必要です。
本記事ではメルカリでのMicroservices上で使われてるサービスを理解するため自分が行ったTerraformによるGCPプロジェクトの構築からSpinnakerによる自動デプロイまでの方法を紹介します。
Spinnakerについては下記の記事もご参照ください!
tech.mercari.com
tech.mercari.com
本記事では、下記のすべてが実現しているプロジェクトを作ることをゴールとします
- GoogleCloudPlatform上でProjectの作成
-
- ServiceAccountのcredentialファイル(JSON形式)を作成・ダウンロード
- gcloudのconfigurationsの設定
基本的に下記の公式のGetting Startedを参考に、作成するのをKubernetes ClusterとしLocal Valueを使っています。
公式ドキュメントのリンクを載せているので適宜参考にしてください。
ちなみに自分はAccess Private Docker Registryの設定等をやるのを忘れておりハマったりしてました
ちなみにHalyardを使わなくてもGoogle Cloud Platform Marketplaceから1クリックでSpinnaker環境を構築できたりもします。
次に実際のアプリケーション部分の構築に入ります。
messageに
最終的なディレクトリ構成は下記のようにしています。
Service名は、valueServiceとします。その中でSayRequestとSayResonseを作成します。
実際に動かすためにserveするためのコマンドを実装します
今日の記事は、アプリケーションそれぞれの表面的な部分しかなぞっていません。もちろん本番環境で使うなどできないようなものです(実際は監視ツール群などが必要でさらにMicroservices同士でやりとりも必要...)
それでも新しい技術に触れ動かすことができるというのは楽しいものであり、またこれを実際に深い部分まで理解してメルカリ上で動かしているチームがいるというのも非常に尊敬するところであります。
弊社では、新しい技術を学ぶことを楽しめるエンジニアを引き続き募集しています。
最近は東京のみならず福岡にも支社できてるので興味ある方よかったら応募してみてください。
careers.mercari.com
最後まで読んでいただきありがとうございました。
明日 3日目の執筆担当は @shoe116 です。引き続きお楽しみください
Mercari Advent Calendar 2018 の2日目はCrossUXチームの@mkazutaka(twitterは@makazutaka)がお送りします。
昨日のアドベントカレンダーに@stanakaさんが取り上げているようにメルカリではMicroservices化に向けて開発が進んでおります。その流れに乗るように前QまでPHPを使って開発していた自分も今QからMicroservicesで実現されているサービスでの開発を行っております。
tech.mercari.com
メルカリではMicroservicesの実現にあたってGoogleCloudPlatform(GCP)、Terraform、Docker、Kubernetes、Halyard、gRPC、Goといったさまざまなサービスからフレームワーク、言語を利用しています。
メルカリでのMicroservices上での開発をする以上、これらに対して多少なりとも理解が必要です。
本記事ではメルカリでのMicroservices上で使われてるサービスを理解するため自分が行ったTerraformによるGCPプロジェクトの構築からSpinnakerによる自動デプロイまでの方法を紹介します。
Spinnakerについては下記の記事もご参照ください!
tech.mercari.com
tech.mercari.com
本記事では、下記のすべてが実現しているプロジェクトを作ることをゴールとします
- Terraformを用いてGCP上にKubernetes clusterが作成されている
- Terraformを用いてGCP上に必要なService Accountが作成されている
- Kubernetes Cluster上でSpinnakerが動作している
- Kubernetes Cluster上でgRPCプロジェクトが1つ動いている
- Kubernetes Cluster上でgRPCプロジェクトにリクエストを投げることができる、またレスポンスを受け取ることができる
- Gitのmasterブランチのレポジトリ内容を更新するとSpinnaker上で自動デプロイ・ビルドが起こる
- 各アプリケーションの説明
- 各アプリケーションのインストール方法
- 各アプリケーションのコードの詳細な解説
||*'-') < gcloud --version Google Cloud SDK 226.0.0 cloud-build-local kubectl 2018.09.17 ||*'-') < hal --version 1.12.0-20181024113436 ||*'-') < terraform --version Terraform v0.11.10始める前に以下の準備が必要です。
- GoogleCloudPlatform上でProjectの作成
-
Kubernetes Engine API
と Compute Engine API
を有効化 - ServiceAccountのcredentialファイル(JSON形式)を作成・ダウンロード
- gcloudのconfigurationsの設定
# 自分は下記状態で始めます。Project名等は適宜自分が設定したものに変えてください。 ||*'-') < gcloud config list [compute] region = asia-northeast1 zone = asia-northeast1-a [core] account = ***@gmail.com disable_usage_reporting = True project = advent20181202はじめにGoogle Kubernetes Engine上にKubernetes ClusterをTerraformで作成します。
基本的に下記の公式のGetting Startedを参考に、作成するのをKubernetes ClusterとしLocal Valueを使っています。
locals { project = "advent20181202" region = "asia-east1" zone = "asia-northeast1-a" kubernetes = { name = "terraform-cluster" } network = { name = "terraform-network" } } provider "google" { project = "${local.project}" region = "${local.region}" zone = "${local.zone}" credentials = "${file("account.json")}" } resource "google_container_cluster" "cluster" { name = "${local.kubernetes["name"]}" initial_node_count = 3 network = "${google_compute_network.vpc_network.self_link}" enable_legacy_abac = true } resource "google_compute_network" "vpc_network" { name = "${local.network["name"]}" auto_create_subnetworks = "true" }作成後、terraform applyをしてKubernetes Clusterを作成することができます。
||*'-') < terraform init ||*'-') < terraform plan # check ||*'-') < terraform applyつぎに、作成したKubernetes上にHalyardを使いSpinnakerをデプロイします。
公式ドキュメントのリンクを載せているので適宜参考にしてください。
ちなみに自分はAccess Private Docker Registryの設定等をやるのを忘れておりハマったりしてました
#!/usr/bin/env bash KUBERNETES_CLUSTER=terraform-cluster ########## 1.Download Credential gcloud container clusters get-credentials ${KUBERNETES_CLUSTER} ########## 2.Adding Account to Halyard ########## ref: https://www.spinnaker.io/setup/install/providers/kubernetes-v2/#adding-an-account ACCOUNT=my-k8s-v2-account hal config provider kubernetes enable hal config provider kubernetes account add my-k8s-v2-account \ --provider-version v2 \ --context $(kubectl config current-context) hal config features edit --artifacts true ########## 3. Distribute installation ########## ref: https://www.spinnaker.io/setup/install/environment/#distributed-installation hal config deploy edit --type distributed --account-name ${ACCOUNT} hal shutdown ########## 4. Choose Storage Service ########## ref: https://www.spinnaker.io/setup/install/storage/gcs/ SERVICE_ACCOUNT_NAME=spinnaker-gcs-account SERVICE_ACCOUNT_DEST=~/.gcp/gcs-account.json SA_EMAIL=$(gcloud iam service-accounts list \ --filter="displayName:$SERVICE_ACCOUNT_NAME" \ --format='value(email)') PROJECT=$(gcloud info --format='value(config.project)') #-- create service account gcloud iam service-accounts create \ha ${SERVICE_ACCOUNT_NAME} \ --display-name ${SERVICE_ACCOUNT_NAME} #-- add iam=policy to serviceAccount gcloud projects add-iam-policy-binding ${PROJECT} \ --role roles/storage.admin --member serviceAccount:${SA_EMAIL} #-- create service-account key mkdir -p $(dirname ${SERVICE_ACCOUNT_DEST}) gcloud iam service-accounts keys create ${SERVICE_ACCOUNT_DEST} \ --iam-account ${SA_EMAIL} #-- create storage BUCKET_LOCATION=us hal config storage gcs edit --project ${PROJECT} \ --bucket-location ${BUCKET_LOCATION} \ --json-path ${SERVICE_ACCOUNT_DEST} hal config storage edit --type gcs ########## 5. Container Registry ########## ref. https://www.spinnaker.io/setup/install/providers/docker-registry/#google-container-registry ADDRESS=gcr.io SERVICE_ACCOUNT_NAME=spinnaker-gcr-account SERVICE_ACCOUNT_DEST=~/.gcp/gcr-account.json gcloud iam service-accounts create \ ${SERVICE_ACCOUNT_NAME} \ --display-name ${SERVICE_ACCOUNT_NAME} SA_EMAIL=$(gcloud iam service-accounts list \ --filter="displayName:$SERVICE_ACCOUNT_NAME" \ --format='value(email)') PROJECT=$(gcloud info --format='value(config.project)') gcloud projects add-iam-policy-binding ${PROJECT} \ --member serviceAccount:${SA_EMAIL} \ --role roles/browser gcloud projects add-iam-policy-binding ${PROJECT} \ --member serviceAccount:${SA_EMAIL} \ --role roles/storage.admin mkdir -p $(dirname ${SERVICE_ACCOUNT_DEST}) gcloud iam service-accounts keys create ${SERVICE_ACCOUNT_DEST} \ --iam-account ${SA_EMAIL} PASSWORD_FILE=${SERVICE_ACCOUNT_DEST} hal config provider docker-registry account add my-docker-registry \ --address ${ADDRESS} \ --username _json_key \ --password-file ${PASSWORD_FILE} ########## 6. Access Private Docker Registry ########## ref. https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ SECRETNAME=reg-secret SERVICE_ACCOUNT_DEST=~/.gcp/gcr-account.json kubectl create secret docker-registry ${SECRETNAME} \ --docker-server=https://gcr.io \ --docker-username=_json_key \ --docker-email=user@example.com \ --docker-password="$(cat ${SERVICE_ACCOUNT_DEST})" ########## 7. Deploy ########## ref: https://www.spinnaker.io/setup/install/deploy/ VERSION=1.10.1 hal config version edit --version ${VERSION} hal deploy apply # 確認 kubectl get pods --namespace spinnakerここまで来たらSpinnakerの環境構築は終わりです。
ちなみにHalyardを使わなくてもGoogle Cloud Platform Marketplaceから1クリックでSpinnaker環境を構築できたりもします。
次に実際のアプリケーション部分の構築に入ります。
messageに
Go
と入力したらレスポンスのメッセージにBold
と返すアプリケーションを作りましょう。最終的なディレクトリ構成は下記のようにしています。
||*'-') < tree . ├── client │ └── main.go ├── proto │ └── value.proto ├── server │ └── main.go └── value ├── server.go └── value.pb.go最初にprotoファイルを定義します。
Service名は、valueServiceとします。その中でSayRequestとSayResonseを作成します。
// vim proto/value.proto syntax = "proto3"; package value; service valueService { rpc Say (SayRequest) returns (SayResponse); } message SayRequest { string message = 1; } message SayResponse { string message = 1; }上記のファイルを完成させるとprotoファイルをコンパイルします。
||*'-') < protoc --proto_path=proto --go_out=plugins=grpc:value value.protoそしてmainロジックを実装します
// vim value/server.go package value import ( "context" ) type Server interface { Say(ctx context.Context, in *SayRequest) (*SayResponse, error) } func New() (Server, error) { return &server{}, nil } type server struct{} func (s *server) Say(ctx context.Context, in *SayRequest) (*SayResponse, error) { if in.Message == "Go" { return &SayResponse{ Message: "Bold!", }, nil } return &SayResponse{ Message: "Mercari", }, nil }ここまででロジックは完成です。
実際に動かすためにserveするためのコマンドを実装します
// vim server/main.go package main import ( "google.golang.org/grpc" "log" "net" "github.com/mkazutaka/value-service/value" ) const ( port = ":50001" ) func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() server, nil := value.New() value.RegisterValueServiceServer(s, server) // Register reflection service on gRPC server. if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }次にserverにアクセスするためのクライアント側を作成します
// vim client/main.go package main import ( "golang.org/x/net/context" "google.golang.org/grpc" "log" "time" pb "github.com/mkazutaka/value-service/value" ) const ( address = "localhost:50001" defaultName = "world" ) func main() { // Set up a connection to the server. conn, err := grpc.Dial(address, grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := pb.NewValueServiceClient(conn) // Contact the server and print out its response. ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() req := &pb.SayRequest{Message: "Go"} log.Printf("Say: %s", req.Message) r, err := c.Say(ctx, req) if err != nil { log.Fatalf("could not: %v", err) } log.Printf("Ans: %s", r.Message) }
||*'-') < go run server/main.go ||*'-') < go run client/main.go 2018/11/29 16:55:48 Say: Go 2018/11/29 16:55:48 Ans: Bold!
アプリケーション側は終わりです
最後に、Spinnakerを使った自動デプロイを設定しようとしたのですが、ちょっと長いのでまた今度にします!(こっそり更新する予定です)今日の記事は、アプリケーションそれぞれの表面的な部分しかなぞっていません。もちろん本番環境で使うなどできないようなものです(実際は監視ツール群などが必要でさらにMicroservices同士でやりとりも必要...)
それでも新しい技術に触れ動かすことができるというのは楽しいものであり、またこれを実際に深い部分まで理解してメルカリ上で動かしているチームがいるというのも非常に尊敬するところであります。
弊社では、新しい技術を学ぶことを楽しめるエンジニアを引き続き募集しています。
最近は東京のみならず福岡にも支社できてるので興味ある方よかったら応募してみてください。
careers.mercari.com
最後まで読んでいただきありがとうございました。
明日 3日目の執筆担当は @shoe116 です。引き続きお楽しみください
オリジナルのエンクロージャ: |
コメント
コメントを投稿