부트 캠프 시작하기전에 구글 쉘 창을 우선적으로 실행시켰습니다.

gcloud auth list

gcloud config list project
$ gcloud config set account `ACCOUNT`
gcloud config set compute/zone asia-northeast3-a
gcloud config set compute/region asia-northeast3

존설정

 

ㅡ. Legacy Network

Google Cloud Engine에서는 단일 네트워크 IPv4 프리픽스 범위 정의 하고 해당 네트워크는 모든 Cloud Platform 지역에 걸쳐 있습니다.

ㅡ. Regional Subnetworks

네트워크 특정 지역에 있는 영역에서는 생성 되는 인스턴스에 subnetwork IP prefix range가 할당됩니다.

ㅡ. 서브넷 확인

$ gcloud compute networks subnets list

 

ㅡ. VM생성(2대)

서로 다른 지역에 2개의 VM을 생성합니다.

$ gcloud compute instances create instance-1 --zone [zone-name]
$ gcloud compute instances create instance-2 --zone [zone-name]
$ gcloud compute instances list 

instance들의 상세정보를 확인할 수 있습니다.

 

ㅡ. 커스텀 서브넷

네트워크 각 지역에 대한 서브 네트워크 IP범위를 수동으로 정의할 수 있습니다. 인스턴스 생성시 인스턴스 IP를 할당해야하는 리전의 서브 네트워크를 지정합니다.

$ gcloud compute networks create custom-network1 --subnet-mode custom

network topology를 생성합니다. 

$ gcloud compute networks subnets create subnet-seoul-192 \
--network custom-network1 \
--region asia-northeast3 \
--range 192.168.1.0/24 

 

이름은 subnet-seoul-192 리전은 asia-northeast3 네트워크는 custom-network1 IP범위는 192.168.1.0/24 입니다.

$ gcloud compute networks subnets list

default network를 포함한 custom subnet을 확인해볼 수 있습니다.

 

각각 만든 서브넷 위치에 VM인스턴스를 생성합니다.

$ gcloud compute instances create instance-3 \
--zone asia-northeast3-a \
--subnet subnet-seoul-192

이름이 instance-3이고 zone이 asia-northeast3-a 머신타입은 기본적으로 n1-standard-1 으로 구성되어있습니다.

$ gcloud compute instances create instance-4 \
--zone asia-northeast1-c \
--subnet subnet-tokyo-192

마찬가지로 instance-4도 생성합니다.

$ gcloud compute networks subnets list | grep asia-northeast && gcloud compute instances list

asia-northeast network와 똑같은것을 찾고 compute instance list를 보여달라는 의미입니다.

인스턴스가 생성된것을 확인할 수 있습니다.

ㅡ. Compute Engine 기반 웹 애플리케이션 서버 구성

$ gcloud services enable compute.googleapis.com

Compute Engine API를 활성화 해주었습니다.

$ gsutil mb gs://fancy-store-$DEVSHELL_PROJECT_ID

GCS를 만들어 줍니다. (built code 들을 GCS bucket에 저장하기 위해서 입니다.)

$ git clone https://github.com/googlecodelabs/monolith-to-microservices.git

소스 레파지토리 다운로드 진행하고

$ cd ~/monolith-to-microservices
$ ./setup.sh

실행합니다.

*.sh 는 shell sscript 파일입니다. shell 들이 실행할 수 있는 명령들을 모아놓은 파일 입니다. shell언어로 만든 파일을 쉘 프로그램 혹은 쉘 스크립트 라고 합니다. 

(*ref : https://emfls.tistory.com/entry/%EC%9E%90%EB%8F%99%ED%99%94%EB%A5%BC-%EC%9C%84%ED%95%9C-sh-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95bash-%EB%AA%85%EB%A0%B9%EC%96%B4)

$ cd microservices
$ npm start

ㅡ. 이슈1

port 중단 시켰을 경우 이미 사용하고 있는 포트 에러가 발생해서 server.js에서 변경해줘야 합니다.

포트 변경을 함께 수행해줘야 합니다.

변경 후 result

결과화면이 잘나오는것을 확인할 수 있습니다.

 

ㅡ. Create GCE instances

1단계. Create Startup Script<Create a startup script to configure instances.>

Open Editor > File > New File 을 진행합니다.

#!/bin/bash



# Install logging monitor. The monitor will automatically pick up logs sent to
# syslog.
curl -s "https://storage.googleapis.com/signals-agents/logging/google-fluentd-install.sh" | bash
service google-fluentd restart &

# Install dependencies from apt
apt-get update
apt-get install -yq ca-certificates git build-essential supervisor psmisc

# Install nodejs
mkdir /opt/nodejs
curl https://nodejs.org/dist/v8.12.0/node-v8.12.0-linux-x64.tar.gz | tar xvzf - -C /opt/nodejs --strip-components=1
ln -s /opt/nodejs/bin/node /usr/bin/node
ln -s /opt/nodejs/bin/npm /usr/bin/npm

# Get the application source code from the Google Cloud Storage bucket.
mkdir /fancy-store
gsutil -m cp -r gs://fancy-store-[DEVSHELL_PROJECT_ID]/monolith-to-microservices/microservices/* /fancy-store/

# Install app dependencies.
cd /fancy-store/
npm install

# Create a nodeapp user. The application will run as this user.
useradd -m -d /home/nodeapp nodeapp
chown -R nodeapp:nodeapp /opt/app

# Configure supervisor to run the node app.
cat >/etc/supervisor/conf.d/node-app.conf << EOF
[program:nodeapp]
directory=/fancy-store
command=npm start
autostart=true
autorestart=true
user=nodeapp
environment=HOME="/home/nodeapp",USER="nodeapp",NODE_ENV="production"
stdout_logfile=syslog
stderr_logfile=syslog
EOF

supervisorctl reread
supervisorctl update

*스크립트 설명

Logging 에이전트 : syslog에서 자동으로 로그를 수집

*Logging 에이전트 : 타사 애플리케이션과 시스템 소프트웨어의 로그를 Logging으로 스트리밍 합니다. 

Node.js 및 Supervisor 설치, Supervisor앱을 데몬으로 실행

*Supervisor : 서비스를 모니터링 하며 서버를 온오프가 가능하도록 합니다.

GCS Bucket에서 앱의 소스 코드 복제, 종속 항목 설치

앱을 실행하도록 Supervisor 구성

 

 

스크립트 작성 후에, 

$ echo $DEVSHELL_PROJECT_ID

결과 값을

파란색으로 묶은 곳에

 

해당 OUTPUT을 대입합니다.

 

2단계. Copy code into Cloud Storage bucket<Clone source code and upload to Google Cloud Storage.>

$ gsutil cp ~/monolith-to-microservices/startup-script.sh gs://fancy-store-$DEVSHELL_PROJECT_ID

startup-script.sh를 gcs 로 옮깁니다. 상품 목적상 environment variables는 코드 밖에 저장하는걸 권고합니다.

$ cd ~
rm -rf monolith-to-microservices/*/node_modules
gsutil -m cp -r monolith-to-microservices   gs://fancy-store-$DEVSHELL_PROJECT_ID/

node_modules를 지우고 bucket에 옮깁니다.

 

*rm -rf : 디렉토리 삭제

*gsutil cp : Copy file and objects (

option -r : 버킷 및 버킷 하위 디렉토리를 반복적으로 복사할 수 있습니다. 이 옵션을 사용하지 않으면 현재 버킷 디렉토리 수준에서 개체를 복사하고 하위 디렉토리를 건너뛰게 됩니다. 

-m : 아주 큰 파일의 수를 옮기려고 할때 parallel multi-threaded 를 수행할 수 있습니다. 

)

 

e.g) 

gsutil cp -r dir gs://my-bucket/data

This causes ``dir`` and all of its files and nested subdirectories to be copied under the specified destination, resulting in objects with names like ``gs://my-bucket/data/dir/a/b/c``.

Similarly, you can download from bucket subdirectories using the following command:

 

3단계. Deploy backend instance<Deploy a Compute Engine instance to host the backend microservices.>

$ gcloud compute instances create backend \
   --machine-type=n1-standard-1 \
   --subnet subnet-seoul-192 \
   --tags=backend \
   --metadata=startup-script-url=https://storage.googleapis.com/fancy-store-$DEVSHELL_PROJECT_ID/startup-script.sh

storage에 저장한 startup-script.sh를 가져와서 instance를 생성하게 됩니다.

 

4단계. Configure connection to backend<Reconfigure the frontend code to utilize the backend microservices instance.>

frontend 애플리케이션을 배포하기에 앞서서, 배포된 backend를 지정해서 환경설정을 업데이트할 필요가 있습니다.

$ gcloud compute instances list

output 확인합니다.

external ip 를 복사합니다.

 

monolith-to-microservices > react-app, view > toggle hidden files

env 파일을 확인할 수 있습니다.

$ cd ~/monolith-to-microservices/react-app
$ npm install && npm run-script build

react-app을 rebuild 시키고, frontend code를 업데이트 합니다. Backend 외부 ip를 front-end에 설정하고 rebuild.

$ cd ~
rm -rf monolith-to-microservices/*/node_modules
$ gsutil -m cp -r monolith-to-microservices gs://fancy-store-$DEVSHELL_PROJECT_ID/

다시 구글 클라우드 스토리지 버킷에 옮겨둡니다.

 

ㅡ. Deploy frontend instance<Deploy a Compute Engine instance to host the frontend microservice.>

$ gcloud compute instances create frontend \
   --machine-type=n1-standard-1 \
   --subnet subnet-seoul-192 \
   --tags=frontend \
    --metadata=startup-script-url=https://storage.googleapis.com/fancy-store-$DEVSHELL_PROJECT_ID/startup-script.sh 

frontend 이름으로 인스턴스를 생성, backend 인스턴스 생성과 유사합니다. tags를 frontend라고 단 이유는 방화벽 목적이 있습니다.

 

ㅡ. Configure Network

$ gcloud compute firewall-rules create fw-fe \
    --allow tcp:8085 \
    --network custom-network1 \
    --target-tags=frontend
$ gcloud compute firewall-rules create fw-be \
    --allow tcp:8086-8087 \
    --network custom-network1 \
    --target-tags=backend
$ gcloud compute firewall-rules create ssh \
    --allow tcp:22 \
    --network custom-network1

8085 frontend 방화벽을 열어주고 8086, 8087 backend 방화벽으로 열어줍니다. 방화벽 명령어들은 인스턴스를 만들어 지는 동안에 tags를 사용합니다.

 

gcloud compute instances list

프론트엔드의 external IP 항해하기 위해서 address를 알아야 합니다.  

watch -n 2 curl http://[FRONTEND_ADDRESS]:8080

frontend 인스턴스의 external ip를 대체하세요! 실행중인 애플리케이션의 모니터할 수 있습니다.

ㅡ. 추가

p.s

ps 명령어는 현재 실행중인 프로세스 및 목록과 상태를 보여줍니다. 

(*ref : https://jhnyang.tistory.com/268

 

curl 명령어 

curl이라는 http 메시지를  쉘상에서 요청하여 결과를 확인합니다. 

e.g) curl localhost

(*ref : https://jhnyang.tistory.com/268)

 

netstat명령어 통한 네트워크 상태확인

netstat [option] 

e.g) netstat -aln 

netstat -an : | grep 포트번호 : 특정 포트가 사용중인지 확인합니다.

netstat -nlpt : TCP listening 상태의 포트와 프로그램을 보여줍니다.

 

ㅡ. 웹결과물(외부아이피:8080)

ㅡ. Create Managed Instance Groups

관리 형 인스턴스 그룹은 인스턴스를 사전에 사용 가능한 상태, 즉 RUNNING 상태로 유지하여 앱의 고 가용성을 유지합니다.

프런트 엔드 및 백엔드 인스턴스에 관리 형 인스턴스 그룹을 사용하여 자동 복구, 부하 분산, 자동 확장, 롤링 업데이트를 제공합니다.

 

인스턴스 템플릿을 사용하여 관리 형 인스턴스 그룹에 인스턴스를 만들거나 개별 인스턴스를 만들 수도 있습니다.

 

gcloud compute instances stop frontend
gcloud compute instances stop backend

compute engine을 멈춥니다.

 

gcloud compute instance-templates create fancy-fe \
    --source-instance=frontend
    
gcloud compute instance-templates create fancy-be \
    --source-instance=backend

인스턴스 템플릿을 생성합니다.

gcloud compute instance-templates list

인스턴스 템플릿 리스트를 확인합니다.

 

ㅡ. Create Managed instance group

gcloud compute instance-groups managed create fancy-fe-mig \
    --base-instance-name fancy-fe \
    --size 2 \
    --template fancy-fe
    
gcloud compute instance-groups managed create fancy-be-mig \
    --base-instance-name fancy-be \
    --size 2 \
    --template fancy-be

관리할 인스턴스 그룹을 생성합니다. 각각 frontend 와 backend로 이루어져 있습니다. 

인스턴스 그룹은 인스턴스 템플릿을 사용합니다. 각 그룹은 시작할 때 2개의 인스턴스로 구성됩니다. 

 

gcloud compute instance-groups set-named-ports fancy-fe-mig \
    --named-ports frontend:8080
    
gcloud compute instance-groups set-named-ports fancy-be-mig \
    --named-ports orders:8081,products:8082

frontend 는 8080 에서, backend는 orders 8081 products 8082에서 동작합니다.

여기서 포트는 비표준 포트 라고 합니다. 명명된 포트를 만들어줘야 하는데 키 : 값 쌍의 메타데이터로 구성할 수 있습니다. 이름이 지정된 포트를 인스턴스 그룹에 할당할 수 있고 그룹의 모든 인스턴스에서 서비스를 사용할 수 있습니다. 나중에 HTTP 부하 분산 서비스에 사용됩니다.

 

ㅡ. Configure autohealing 

애플리케이션 자체의 가용성을 개선하고 응답하는지 확인하려면 관리 형 인스턴스 그룹에 대한 자동 복구 정책을 구성

앱이 응답하는지 확인하는 것은 인스턴스가 기본 동작 인 RUNNING 상태에 있는지 확인

 

헬스체크는 로드밸런싱을 위한것인데, 인스턴스가 유저의 트래픽을 받았는지 확인할 수 있습니다. 인스턴스가 응답을 받았는지 빠르게 캐치할 수 있습니다. 또, 헬스 체크의 자동복구는 사전대책을 강구해서 실패한 인스턴스를 대체합니다.

 

Note: Separate health checks for load balancing and for autohealing will be used. Health checks for load balancing can and should be more aggressive because these health checks determine whether an instance receives user traffic. You want to catch non-responsive instances quickly so you can redirect traffic if necessary. In contrast, health checking for autohealing causes Compute Engine to proactively replace failing instances, so this health check should be more conservative than a load balancing health check.( 로드 밸런서 헬스체크와 자동힐링 헬스체크와의 차이 )

gcloud compute health-checks create http fancy-fe-hc \
    --port 8080 \
    --check-interval 30s \
    --healthy-threshold 1 \
    --timeout 10s \
    --unhealthy-threshold 3
    
gcloud compute health-checks create http fancy-be-hc \
    --port 8081 \
    --request-path=/api/orders \
    --check-interval 30s \
    --healthy-threshold 1 \
    --timeout 10s \
    --unhealthy-threshold 3

health check를 만듭니다. instance를 만들어 낼 수 있는 (unhealthy) 를 3회 연속적으로 반환하게 되면 > frontend, backend에 대해서

gcloud compute firewall-rules create allow-health-check \
    --allow tcp:8080-8081 \
    --source-ranges 130.211.0.0/22,35.191.0.0/16 \
    --network custom-network1

방화벽 규칙을 생성합니다. health check를 승인하기 위해서 마이크로서비스의 포트 8080, 8081을 허락합니다.

gcloud compute instance-groups managed update fancy-fe-mig \
    --health-check fancy-fe-hc \
    --initial-delay 300
    
gcloud compute instance-groups managed update fancy-be-mig \
    --health-check fancy-be-hc \
    --initial-delay 300

각각의 서비스에 헬스체크를 적용합니다.

방화벽 생성부터 health check를 각 서비스마다 달아주었습니다.

 

ㅡ. Create Load Balancers

HTTP (S) 부하 분산기를 사용하여 프런트 엔드 및 백엔드 마이크로 서비스에 트래픽을 제공하고 매핑을 사용하여 경로 지정 규칙에 따라 적절한 백엔드 서비스로 트래픽을 보냅니다. 

이 실습에서는 트래픽에 HTTP (S) 부하 분산기를 사용합니다.

1. HTTP 프록시로 보냅니다.

2. URL 맵에 대해 각 요청을 확인하여 요청에 적합한 백엔드 서비스를 결정

3. 백엔드 서비스는 연결된 백엔드의 제공 용량, 영역, 인스턴스 상태에 따라 각 요청을 적절한 백엔드로 보냅니다.  

4. 부하 분산기와 인스턴스 간의 세션은 HTTP, HTTPS 또는 HTTP / 2 프로토콜을 사용

 

단, 상품화할때는 HTTPS를 권고

gcloud compute http-health-checks create fancy-fe-frontend-hc \
  --request-path / \
  --port 8080
  
 gcloud compute http-health-checks create fancy-be-orders-hc \
  --request-path /api/orders \
  --port 8081
  
  gcloud compute http-health-checks create fancy-be-products-hc \
  --request-path /api/products \
  --port 8082

health check를 생성합니다. 인스턴스가 옮길 트래픽을 각 서비스마다 

헬스체크는 로드 밸런서를 위한것이다. 로드밸런서로부터 트래픽을 직접 핸들링한다. 매니지드 인스턴스 그룹들이 인스턴스들을 재생산하게 되는 원인이 되지는 않습니다. 

gcloud compute backend-services create fancy-fe-frontend \
  --http-health-checks fancy-fe-frontend-hc \
  --port-name frontend \
  --network custom-network1 \
  --global

gcloud compute backend-services create fancy-be-orders \
  --http-health-checks fancy-be-orders-hc \
  --port-name orders \
  --network custom-network1 \
  --global
  
 gcloud compute backend-services create fancy-be-products \
  --http-health-checks fancy-be-products-hc \
  --port-name products \
  --network custom-network1 \
  --global

백엔드 서비스를 생성합니다. 로드밸런스 트래픽을 타겟으로 할 수 있는 

백엔드 서비스는 사용될 것입니다. 헬스체크로 내가 만든 포트에 

gcloud compute backend-services add-backend fancy-fe-frontend \
  --instance-group fancy-fe-mig \
  --instance-group-zone asia-northeast3-a \
  --global
  
gcloud compute backend-services add-backend fancy-be-orders \
  --instance-group fancy-be-mig \
  --instance-group-zone asia-northeast3-a \
  --global
  
gcloud compute backend-services add-backend fancy-be-products \
  --instance-group fancy-be-mig \
  --instance-group-zone asia-northeast3-a \
  --global

백엔드 서비스는 Cloud Load Balancing이 트래픽을 분산하는 방법을 정의합니다. 백엔드 서비스 구성에는 백엔드에 연결하는 데 사용되는 프로토콜, 다양한 배포 및 세션 설정, 상태 확인, 제한 시간 등의 다양한 값 집합이 포함됩니다. 이 설정은 부하 분산기의 동작을 세부적으로 제어할 수 있습니다.

백엔드 서비스를 추가합니다. 

gcloud compute url-maps create fancy-map \
  --default-service fancy-fe-frontend

URL맵을 생성하빈다. 어느 URL맵이 어느 backend service를 대상으로 할지 

gcloud compute url-maps add-path-matcher fancy-map \
   --default-service fancy-fe-frontend \
   --path-matcher-name orders \
   --path-rules "/api/orders=fancy-be-orders,/api/products=fancy-be-products"

 

path macher를 만듭니다. 허용할 /api/orders 와 /api/products 패쓰를 어떤 노선으로 그들의 각각 서비스 노선으로 

gcloud compute target-http-proxies create fancy-proxy \
  --url-map fancy-map

프록시를 생성합니다. URL 맵에 연결할 

gcloud compute forwarding-rules create fancy-http-rule \
  --global \
  --target-http-proxy fancy-proxy \
  --ports 80

global 포워딩 규칙을 생성합니다. public IP 주소를 연결할 그리고 프록시로 연결

 

ㅡ. Update Configuration

new static IP address 를 가질것 입니다. frontend의 코드를 업데이트하고 임시 주소 대신에 새로운 어드레스를 가리키세요. 사용될 것입니다. 이전에 사용했었던 그리고 이것은 bakend 인스턴스를 가리킬 겁니다.

cd ~/monolith-to-microservices/react-app/

react-app 으로 이동하고 이곳은 .env 파일을 보관하고 있고 환경설정을 유지할 수 있습니다.

gcloud compute forwarding-rules list --global

로드밸런서의 IP주소를 확인합니다.

로드밸런서의 public IP 로 변경하였습니다. 위에서는 external IP로 표현됩니다.

포트는 지웁니다. 로드밸런서는 환경설정되어있습니다. 포워딩하기 위한

cd ~/monolith-to-microservices/react-app
npm install && npm run-script build

react-app을 다시 빌드하고 frontend code를 업데이트 하세요.

cd ~
rm -rf monolith-to-microservices/*/node_modules
gsutil -m cp -r monolith-to-microservices gs://fancy-store-$DEVSHELL_PROJECT_ID/

그리고 나서 application 코드를 버킷에 업로드하세요.

 

ㅡ. Update the frontend instances

gcloud compute instance-groups managed rolling-action replace fancy-fe-mig \
    --max-unavailable 100%

이제 새 코드와 구성이 있으므로 관리 형 인스턴스 그룹 내의 frontend 인스턴스가 새 코드를 가져 오도록 합니다. 인스턴스가 시작시 코드를 가져 오므로 rolling restart 명령을 실행할 수 있습니다.

--max-unavailable 명령어는 인스턴스의 가용성을 위해 다른 인스턴스들이 재시작하는 동안에 인스턴스들을 유지하게 해줍니다.

ㅡ. Test the website

watch -n 2 gcloud compute instance-groups list-instances fancy-fe-mig

rolling-action replace 명령어를 실행 한 후 약 30 초 동안 기다렸다가 인스턴스를 처리 할 시간을 준 다음 인스턴스가 목록에 나타날 때까지 관리 형 인스턴스 그룹의 상태를 확인합니다.

watch -n 2 gcloud compute backend-services get-health fancy-fe-frontend --global

서비스가 모두 HEALTHY 상태인지 보려면 위 명령어를 입력하세요.

HEALTHY상태

The application will be accessible via http://[LB_IP] where [LB_IP] is the IP_ADDRESS specified for the Load Balancer, which can be found with the following command:

gcloud compute forwarding-rules list --global

You'll be checking the application later in the lab.

 

ㅡ. Scaling GCE

지금까지 각각 2 개의 인스턴스가 있는 2 개의 관리 형 인스턴스 그룹을 만들었습니다. 이 구성은 잘 작동하지만 부하에 관계 없는 정적 구성입니다. 다음으로 사용률에 따라 자동 확장 정책을 만들어 각 관리 형 인스턴스 그룹을 자동으로 확장합니다.

 

ㅡ. Automatically Resize by Utilization

gcloud compute instance-groups managed set-autoscaling \
  fancy-fe-mig \
  --max-num-replicas 2 \
  --target-load-balancing-utilization 0.60
gcloud compute instance-groups managed set-autoscaling \
  fancy-be-mig \
  --max-num-replicas 2 \
  --target-load-balancing-utilization 0.60

To create the autoscaling policy, execute the following (--max-num-replicas는 최대로 띄울 인스턴스의 개수를 입력합니다. 여기서는 Qwiklabs 시스템의 제약으로 2로 지정합니다):

 

이 명령어는 사용률이 60 %를 초과하면 인스턴스를 자동으로 추가하고 부하 분산기가 사용률이 60 % 미만이면 인스턴스를 제거하는 관리 형 인스턴스 그룹에 자동 확장 처리를 만듭니다.

 

gcloud compute forwarding-rules list --global && gcloud compute instance-groups managed describe --zone asia-northeast3-a fancy-fe-mig | head -n 15

로드밸런서 결과

 

ㅡ. Update the website

시나리오 : 마케팅 팀이 사이트의 홈페이지 변경을 요청했습니다. 그들은 당신의 회사가 누구이고 당신이 실제로 무엇을 판매하는지에 대해 더 많은 정보를 제공해야 한다고 생각합니다.

작업 : 홈페이지에 텍스트를 추가하여 마케팅 팀을 행복하게 만드세요! 개발자 중 한 명이 이미 index.js.new라는 파일 이름으로 변경 사항을 만든 것 같습니다. 이 파일을 index.js에 복사하면 변경 사항이 반영됩니다. 아래 지침에 따라 적절하게 변경하십시오.

cd ~/monolith-to-microservices/react-app/src/pages/Home
mv index.js.new index.js

updated file을 correct file name으로 카피해주세요.

cat ~/monolith-to-microservices/react-app/src/pages/Home/index.js

변화된것을 확인하고

cd ~/monolith-to-microservices/react-app
npm install && npm run-script build

build 해주세요. React app을 그리고 monolith 퍼블릭 디렉토리에 copy해주세요.

cd ~
rm -rf monolith-to-microservices/*/node_modules
gsutil -m cp -r monolith-to-microservices gs://fancy-store-$DEVSHELL_PROJECT_ID/

버킷에 다시 푸시해주세요.

 

ㅡ. Push changes with rolling replacements.

gcloud compute instance-groups managed rolling-action replace fancy-fe-mig \
    --max-unavailable=100%

업데이트를 실행할수 있도록 모든 인스턴스를 강제로 교체하세요.

 

In this example of a rolling replace, you specifically state that all machines can be replaced immediately through the --max-unavailable parameter. Without this parameter, the command would keep an instance alive while replacing others. For testing purposes, you specify to replace all immediately for speed. In production, leaving a buffer would allow the website to continue serving the website while updating.

 

watch -n 2 gcloud compute instance-groups list-instances fancy-fe-mig

30초 대기, rolling-action replace 명령어가 발행될떄까지 

그리고 managed instance group 상태를 확인, 리스트에서 instance가 나타날때까지

watch -n 2 gcloud compute backend-services get-health fancy-fe-frontend --global

서비스가 HEALTHY하게 나열되는지 확인하려면 위를 실행해보세요.

gcloud compute forwarding-rules list --global

 

Load Balancer 지정된 IP_ADDRESS를 위 명령어로 찾을 수 있습니다.

접속

ㅡ. Simulate Failure

헬스 체크가 동작하고 있는지 확인하기 위해서, 인스턴스에 로그인하고 서비스를 중지합니다.

gcloud compute instance-groups list-instances fancy-fe-mig

인스턴스 이름 찾기

gcloud compute ssh [INSTANCE_NAME]

인스턴스 이름을 복사하고, secure shell을 실행하세요 인스턴스 내에서

sudo supervisorctl stop nodeapp; sudo killall node

애플리케이션을 stop 합니다.

exit

exit으로 인스턴스를 나갑니다.

watch -n 2 gcloud compute operations list \
--filter='operationType~compute.instances.repair.*'

 

repair  operations들을 모니터링합니다.

The managed instance group recreated the instance to repair it.

You can also monitor through the Console - go to Navigation menu > Compute Engine > VM instances.

sllj가 살아난것을 확인할 수 있습니다.

gcloud compute forwarding-rules list --global

웹페이지 업데이트 결과

curl [ip_address]

 

 

ㅡ. Cloud Run 기반 웹 애플리케이션 서버 구성

VM, 클러스터, 포드, 서비스 등을 생성하고 관리하는 모든 오버 헤드로 인해 웹 사이트를 운영하는 것은 어려울 수 있습니다. 이는 대규모 다중 계층(multi-tier) 애플리케이션에는 적합하지만 단순 웹 사이트를 배포하고 표시하려는 경우에는 많은 오버 헤드입니다.

 

Google Cloud의 Google KNative 프레임워크 구현체인 Cloud Run을 사용하면 VM 또는 순수 Kubernetes 기반 배포에서 겪는 인프라 오버헤드 없이 웹 사이트를 관리하고 배포 할 수 있습니다. 이는 관리 관점에서보다 간단한 접근 방식 일뿐만 아니라 웹 사이트에 들어오는 요청이 없을 때 "scale to zero" 로 축소할 수 있는 기능도 제공합니다.

 

Cloud Run은 컨테이너에 '서버리스' 개발을 제공하며 자체 Google Kubernetes Engine (GKE) 클러스터 또는 Cloud Run에서 제공하는 완전 관리 형 PaaS 솔루션에서 실행할 수 있습니다. 이 실습에서는 후자의 시나리오를 실행합니다.

 

  1. 애플리케이션에서 Docker 컨테이너 만들기
  2. Cloud Run에 컨테이너 배포
  3. 웹 사이트 수정
  4. 다운 타임 없는 새 버전 출시

ㅡ. Architecture diagram

아래에서 배포 및 Cloud Run 호스팅의 흐름을 볼 수 있습니다.

Cloud Shell에서 트리거되는 Cloud Build를 통해 생성 된 Docker 이미지로 시작한 다음 Cloud Shell의 명령에서 Cloud Run에 이미지를 배포합니다.

 

 

ㅡ. Clone Source Repository

여기서는 위에서 VM 기반으로 배포했던 애플리케이션을 동일하게 사용합니다. 소스를 복제해서 Docker 이미지를 만들면 Cloud Run에 바로 배포할 수 있습니다.

cd ~/
rm -rf monolith-to-microservices
git clone https://github.com/googlecodelabs/monolith-to-microservices.git

cd ~/monolith-to-microservices

./setup.sh

배포하기전에 테스트 할 수 있습니다.

cd ~/monolith-to-microservices/monolith
npm start

위 명령어를 통해서 웹 사이트를 시작해봄으로써 테스트 해볼 수 있습니다.

프리뷰로 확인해볼 수 있습니다.

 

ㅡ. Create Docker Container with Cloud Build

이제 소스 파일을 사용할 준비가 되었으므로 애플리케이션을 Dockerize 할 차례입니다!

일반적으로 Docker 컨테이너를 빌드하고 레지스트리로 푸시하여 GKE가 가져올 이미지를 저장하는 2 단계 접근 방식을 취해야 합니다. 삶을 더 쉽게 만들기 위해 Cloud Build를 사용하여 Docker 컨테이너를 빌드하고 단일 명령으로 Container Registry에 이미지를 저장하세요! Docker 파일을 만들고 푸시하는 수동 프로세스를 보려면 여기로 이동하십시오.

Cloud Build는 디렉터리에서 파일을 압축하여 Cloud Storage 버킷으로 복사합니다. 그런 다음 빌드 프로세스는 버킷에서 모든 파일을 가져와 동일한 디렉터리에있는 Dockerfile을 사용하여 Docker 빌드 프로세스를 실행합니다. Docker 이미지에 대해 gcr.io로 호스트에 --tag 플래그를 지정 했으므로 결과 Docker 이미지가 Container Registry로 푸시됩니다.

먼저 Cloud Build API를 사용 설정했는지 확인해야합니다. 활성화하려면 다음 명령을 실행하십시오.

gcloud services enable cloudbuild.googleapis.com

cloud build api 사용설정을 수행합니다.

cd ~/monolith-to-microservices/monolith
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 .

api를 enable하고 build process를 수행합니다.

Navigation menu click Cloud Build > History. 에서 build 히스토리를 확인할 수 있습니다.

build id를 클릭해보면 build에 관한 디테일한 것들을 확인할 수 있습니다. log output을 포함해서

컨테이너 이미지도 확인할 수 있습니다.

 

ㅡ. Deploy Container To Cloud Run

웹 사이트를 컨테이너화하고 컨테이너를 Container Registry에 푸시 했으므로 이제 Cloud Run에 배포 할 차례입니다.

Cloud Run에 배포하는 방법에는 두 가지가 있습니다.

Managed Cloud Run : 모든 컨테이너 수명주기가 Cloud Run 제품 자체에서 관리되는 Platform as a Service 모델입니다. 이 실습에서는 이 접근 방식을 사용하게됩니다.

Cloud Run on GKE : GKE에서 자체 클러스터 및 포드를 가져올 수있는 추가 제어 계층이 있는 Cloud Run입니다. 여기에서 자세한 내용을 읽을 수 있습니다.

 

ㅡ. Command-Line

이전에 빌드한 이미지를 배포할 수 있습니다. managed cloud run 지정된 버전을 고를 수 있습니다. --platform managed.

gcloud services enable run.googleapis.com

Cloud Run API를 활성화 합니다. 

gcloud run deploy --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --platform managed 

다음 코드로 application을 deploy 합니다.

 

ㅡ. Verify deployment

gcloud run services list --platform managed

배포된게 성공적으로 생성되었는지 확인하기 위해 위 명령어를 입력합니다.

 

배포된것을 확인할 수 있습니다.

이 결과는 몇 가지 사항을 보여줍니다. 배포, 배포 한 사용자(사용자 이메일) 및 앱에 액세스하는 데 필요한 수 있는 URL을 볼 수 있습니다. 모든 것이 성공적으로 생성 된 것 같습니다!

 

ㅡ. Create new revision with lower concurrency

애플리케이션을 다시 배포하되 이번에는 매개 변수 중 하나를 조정합니다.

기본적으로 Cloud Run 애플리케이션의 동시성 값은 80입니다. 즉, 각 컨테이너 인스턴스는 한 번에 최대 80개의 요청을 처리합니다. 이것은 하나의 인스턴스가 한 번에 하나의 요청을 처리하는 Functions-as-a-Service 모델과 크게 다릅니다.

동시성 값이 1 (테스트 용) 인 동일한 컨테이너 이미지를 다시 배포하고 어떤 일이 발생하는지 확인합니다.

gcloud run deploy --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --platform managed --concurrency 1

동시성 값이 1로 줄어든것을 확인할 수 있습니다.

이 구성은 테스트에 충분하지만 대부분의 프로덕션 시나리오에서는 여러 동시 요청을 지원하는 컨테이너를 사용합니다.

그래서 다시 배포하지 않고 원래 동시성을 복원합니다.

동시성 값을 기본값 인 "80"으로 다시 설정하거나 값을 "0"으로 설정하여 동시성 제한을 제거하고 기본값 인 최대 값 (80)으로 설정할 수 있습니다.

gcloud run deploy --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:1.0.0 --platform managed --concurrency 80

다른 revision이 생성된것을 확인할 수 있고 

트래픽이 다시 보내졌습니다. 

concurrency는 80으로 돌아왔습니다.

 

gcloud run services describe monolith --platform managed --region asia-northeast1

Cloud Run 배포 결과

Service monolith in region asia-northeast1Traffic: https://monolith-2se4bkyg4q-an.a.run.app 100% LATEST (currently monolith-00002-bag)Last updated on 2020-09-04T07:39:46.555451Z by student-04-800afede2fbf@qwiklabs.net: Revision monolith-00002-bag Image: gcr.io/qwiklabs-gcp-04-3edabe6616aa/monolith:1.0.0 Port: 8080 Memory: 256Mi CPU: 1000m Concurrency: 80 Max Instances: 1000 Timeout: 300s

 

ㅡ. Make Changes To The Website

시나리오 : 마케팅 팀이 사이트의 홈페이지 변경을 요청했습니다. 그들은 당신의 회사가 누구이고 당신이 실제로 무엇을 판매하는지에 대해 더 많은 정보를 제공해야 한다고 생각합니다.

작업 : 홈페이지에 텍스트를 추가하여 마케팅 팀을 행복하게 만드세요! 개발자 중 한 명이 이미 index.js.new라는 파일 이름으로 변경 사항을 만든 것 같습니다. 이 파일을 index.js에 복사하면 변경 사항이 반영됩니다. 아래 지침에 따라 적절하게 변경하십시오.

cd ~/monolith-to-microservices/react-app/src/pages/Home

mv index.js.new index.js

cat ~/monolith-to-microservices/react-app/src/pages/Home/index.js

업데이트된 파일을 현재 파일 이름으로 복사해라.

cd ~/monolith-to-microservices/react-app
npm run build:monolith

React app을 빌드하고 monolith의 퍼블릭 디렉토리에 복사해라.

rebuild 되었다. docker container 그리고 이 빌드된것이 container registry로 publish 되었습니다.

cd ~/monolith-to-microservices/monolith
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 .

이 명령어는 Cloud Build를 트리거하기위한 명령어입니다. 업데이트된 이미지 버전과

다음에는 이 이미지를 사용할 것입니다. application을 업데이트하기위해서 zero downtime 으로

 

ㅡ. Update website with zero downtime

변경 사항이 완료되었으며 마케팅 팀이 업데이트에 만족합니다! 사용자를 방해하지 않고 웹 사이트를 업데이트 할 때입니다.

Cloud Run은 각 배포를 먼저 온라인으로 전환 한 다음 트래픽을 리디렉션하는 새로운 버전으로 취급합니다. 기본적으로 최신 개정에는 서비스에 대한 인바운드 트래픽의 100 %가 할당됩니다. "경로"를 사용하여 서비스 내에서 서로 다른 버전에 서로 다른 비율의 트래픽을 할당 할 수 있습니다.

아래 지침에 따라 웹 사이트를 업데이트하십시오.

명령 줄에서 서비스를 다시 배포하여 다음 명령을 사용하여 이미지를 새 버전으로 업데이트합니다.

gcloud run deploy --image=gcr.io/${GOOGLE_CLOUD_PROJECT}/monolith:2.0.0 --platform managed

 

ㅡ. Verify Deployment

gcloud run services describe monolith --platform managed 

업데이트된 배포를 확인해보세요.

여기에서 서비스가 이제 새 개정에 배포 된 최신 버전의 이미지를 사용하고 있음을 알 수 있습니다.

변경 사항을 확인하려면 Cloud Run 서비스의 외부 URL로 다시 이동하여 애플리케이션 제목이 업데이트되었는지 확인합니다.

다음 명령을 실행하여 서비스를 나열하고 IP 주소를 확인합니다.

변경전)

변경후)

gcloud run services describe monolith --platform managed --region asia-northeast1

Service monolith in region asia-northeast1Traffic: https://monolith-2se4bkyg4q-an.a.run.app 100% LATEST (currently monolith-00003-boz)Last updated on 2020-09-04T07:56:54.794282Z by student-04-800afede2fbf@qwiklabs.net: Revision monolith-00003-boz Image: gcr.io/qwiklabs-gcp-04-3edabe6616aa/monolith:2.0.0 Port: 8080 Memory: 256Mi CPU: 1000m Concurrency: 80 Max Instances: 1000 Timeout: 300s

 

ㅡ. Cloud SQL서버 구성하기

 

두가지를 enable 상태로

 

ㅡ. Createe a Cloud SQL instance

ㅡ. Connect to your instance using the mysql client in the Cloud Shell

gcloud sql connect myinstance --user=root

Cloud SQL실행 해서 연결하세요.

create database fancy;

use fancy;

create table products (
    id varchar(100),
    name varchar(100),
    description varchar(100),
    picture varchar(100),
    cost varchar(100),
    categories varchar(100)
);

INSERT INTO products VALUES("OLJCESPC7Z", "MS -  Vintage Typewriter", "This typewriter looks good in your living room.", "static/img/products/typewriter.jpg", "67.99", "vintage");
INSERT INTO products VALUES("66VCHSJNUP", "MS -  Vintage Camera Lens", "You won't have a camera to use it and it probably doesn't work anyway.", "static/img/products/camera-lens.jpg", "12.49", "photography");
INSERT INTO products VALUES("1YMWWN1N4O", "MS -  Home Barista Kit", "Always wanted to brew coffee with Chemex and Aeropress at home?", "static/img/products/barista-kit.jpg", "124", "cookware");
INSERT INTO products VALUES("L9ECAV7KIM", "MS -  Terrarium", "This terrarium will looks great in your white painted living room.", "static/img/products/terrarium.jpg", "36.45", "gardening");
INSERT INTO products VALUES("2ZYFJ3GM2N", "MS -  Film Camera", "This camera looks like it's a film camera, but it's actually digital.", "static/img/products/film-camera.jpg", "2245", "photography");
INSERT INTO products VALUES("0PUK6V6EV0", "MS -  Vintage Record Player", "It still works.", "static/img/products/record-player.jpg", "65.5", "music");
INSERT INTO products VALUES("LS4PSXUNUM", "MS -  Metal Camping Mug", "You probably don't go camping that often but this is better than plastic cups.", "static/img/products/camp-mug.jpg", "24.33", "cookware");
INSERT INTO products VALUES("9SIQT8TOJO", "MS -  City Bike", "This single gear bike probably cannot climb the hills of San Francisco.", "static/img/products/city-bike.jpg", "789.5", "cycling");
INSERT INTO products VALUES("6E92ZMYYFZ", "MS -  Air Plant", "Have you ever wondered whether air plants need water? Buy one and figure out.", "static/img/products/air-plant.jpg", "12.3", "gardening");
SELECT * FROM products;

GCP 상에 MySQL 인스턴스를 만들었으므로 이제는 Cloud Run 어플리케이션에서 DB에 저장된 데이터를 읽어 오도록 변경해 보겠습니다. 참고로 현재의 monolith-to-microservices 애플리케이션은 JSON 파일에 저장된 데이터를 읽어 오는 구조입니다.

cd ~/monolith-to-microservices/monolith
vi package.json

다음과 같이 depedencies에서 mysql 모듈을 추가

 "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "mysql": "^2.18.1"        // adding this
  }

먼저 다음과 같이 소스를 수정합니다.

cd ~/monolith-to-microservices/monolith/src
vi server.js

아래와 같이 const products 아래에 mysql 연결을 추가. PUBLIC_IP와 ROOT_PASSWORD는 인스턴스 생성 과정에 있음

//Load orders and products for pseudo database
const orders = require("../data/orders.json").orders;
const products = require("../data/products.json").products;

const mysql = require('mysql');
const connection = mysql.createConnection({
  host     : 'PUBLIC_IP',
  user     : 'root',
  password : 'ROOT_PASSWORD',
  database : 'fancy'
});

아래와 같이 JSON 파일에서 읽어오던 데이터를 MySQL DB에서 읽도록 수정

//Get all products
//app.get("/service/products", (req, res) => res.json(products));
app.get("/service/products", (req, res) => {
    connection.query('SELECT * from products', (error, rows) => {
      if (error) throw error;
      console.log('ahniverson info is: ', rows);
      res.json(rows)
    });
  }
);

Cloud Run에서 MySQL에 접속하기 위해서는 몇 가지 방법이 제공됩니다. 첫 번째는 Public IP를 사용하는 방법으로 Proxy를 통해 연결하면 Secure한 방법으로 접속이 가능합니다. 두 번째 방법은 Private IP를 사용하는 방법으로 Serverless VPC Access 기능을 활용합니다. 자세한 내용은 Connecting from Cloud Run (fully managed) to Cloud SQL를 참고하시기 바랍니다.

여기서는 Public IP를 이용한 방법을 사용하되 Proxy는 제외하고 임시로 전체 IP를 열어 접속하는 방식을 사용하겠습니다. Proxy를 사용하는 방식이 궁금하시면 아래 Qwiklabs를 보시기 바랍니다.

Cloud SQL with Terraform

Connect to Cloud SQL from an Application in Kubernetes Engine

콘솔의 메뉴에서 SQL을 선택하고 myinstance를 선택한 후, Connections로 들어갑니다.