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 です。引き続きお楽しみください
| オリジナルのエンクロージャ: |

コメント
コメントを投稿