GCP Netwoking 101에 대한 이해

Networking 101 codelab은 기본적인 네트워크 모니터링 툴 뿐만 아니라 Google Cloud Platform(이하 GCP) 네트워크 구조 전반에 대한 설명과 실습이 포함되어 있습니다.
GCP 네크워크를 이해하는데 좋은 출발점이 될 수 있습니다.

https://codelabs.developers.google.com/codelabs/cloud-networking-101/index.html?index=..%2F..%2Findex#0

Networking 101 codelab 구성도

Imgur

무엇을 배울 수 있을까?

  • 네트워크 관련 오픈 소스 툴을 사용하여 접속 이상유무와 성능을 측정하는 방법
  • Google Compute Engine이 속한 각각의 Region과 Zone 사이의 latency를 측정하는 방법
  • 기본적인 로드 발란싱과 방화벽을 설정하는 방법
  • 네트워크 관련 에러들을 troubleshoting하는 방법

Codelab 준비

신규 Project 생성

GCP에 접속하여 신규 Project를 생성합니다. 여기서는 my-networking-101-codelab으로 신규 Project를 생성했습니다.

Imgur

그리고 Compute Engine API를 사용하기 위하여 GCP Console에서 API Manager로 이동하여 Compute Engine API을 Enable 합니다.

Imgur Imgur Imgur

Project 설정 및 jump host 생성

방금 생성한 Project로 기본 project를 설정하고 jump host를 생성합니다.

$ gcloud config set project <your-project-name>
$ gcloud compute instances create jumphost --scopes cloud-platform --zone us-central1-f --metadata startup-script-url=gs://nw101/startupscript.sh

startupscript.sh

Imgur

jump host는 앞으로 각 region에 생성할 VM 모두에게 접근할 수 있는 VM 인스턴스이며 jump host 생성 시 실행되는 스크립트(startupscript.sh)는 codelab에 필요한 VM 인스턴스와 네트워크를 생성합니다.

Imgur

생성한 VM 인스턴스에 필요한 Tool 설치

Imgur

$ gcloud compute ssh --zone <vm-zone> [vm-name] (e.g. gcloud compute ssh --zone us-central1-f us-vmc)

# Debian
$ sudo apt-get -y update
$ sudo apt-get -y install traceroute mtr tcpdump iperf whois host dnsutils

# CentOS
$ sudo yum check-update 
$ sudo yum -y install epel-release traceroute mtr tcpdump whois bind-utils
$ sudo yum -y install iperf
VM 인스턴스 간의 latency 확인

latency 확인을 위한 ping 사용법입니다.

$ ping -i0.2 us-vm2 #(sends a ping every 200ms)
$ sudo ping -i0.05 us-vm2 -c 1000 #(sends a ping every 50ms, 1000 times)
$ sudo ping -f -i0.05 us-vm2 #(flood ping, adds a dot for every sent packet, and removes one for every received packet)
$ # careful with flood ping without interval, it will send packets as fast as possible, which within the same zone is very fast
$ sudo ping -i0.05 us-vm2 -c 100 -s 1400 #(send larger packets, does it get slower?)

재미있는 내용

VM 1: us-vm1 (Council Bluffs, Iowa)  
VM 2: eu-vm (St. Ghislain, Belgium)  
Distance as the crow flies: 7197.57 km  
Ideal latency: 7197.57 km / 202562 km/s * 1000 ms/s * 2 = 71.07 ms  

먼저 전제는 광케이블의 신호가 초당 202562km를 이동한다는 것입니다. 이제 위의 Ideal latency 계산식을 한번 살펴보면,
위 계산식은 초당(s) 202562km를 이동하므로 거리(7197.57km)를 이 값으로 나누고 ms단위로 계산하기 위해서 1000ms/s 를 곱하고 신호가 왕복이니까 2를 곱합니다. 이렇게 나온 latency 값이 71.07ms입니다.

실제로 측정된 latency가 아래와 같으므로 회선 상태 등을 고려하면 근접한 결과라고 할 수 있습니다.

Observed latency: 100.88 ms (minimum counts)  

GCP region과 zone 정보 : https://cloud.google.com/compute/docs/regions-zones/regions-zones#available

Imgur

위의 표를 보면 Saint Ghislain (europe-west1/벨기에)와 Changhua County ( asia-east1/타이완) 간의 거리가 더 가까운데 latency는 더 깁니다.
이유는 europe-west1 region과 asia-east1 region 간의 직접적인 연결이 없기 때문입니. 결국 asia-east1에서 europe-west1 이동하려면 us-central1 거쳐서 가야합니다.
이런 이유로 오직 하나의 글로벌한 서비스를 한다면 미국에 위치하는 게 latency가 가장 좋은 결과를 가져옵니다.

traceroute

traceroute는 호스트간의 Layer 3 (routing layer) hop을 보여줍니다.

hop아린 데이타통신망에서 각 패킷이 매 노드(또는 라우터)를 건너가는 양상을 비유적으로 표현

$ traceroute www.icann.org
mtr

콘솔에서 호스트간의 Layer 3 (routing layer) hop을 그래픽적으로 보여줍니다.

$ mtr www.icann.org

Imgur

iperf을 이용한 네트워크 성능 측정

eu-vm에서 서버 모드로 실행 (TCP)

$ iperf -s #run in server mode

Imgur

us-vm1에서 클라이언트 모드 실행하여 eu-vm에 접속 (TCP)

$ iperf -c eu-vm #run in client mode, connecting to eu-vm

Imgur

Region간의 bandwidth는 Core 당 2 Gbit/s 의 제약이 있습니다.

eu-vm에서 서버 모드로 실행 (UDP)

$ iperf -s -u #iperf server side (-u UDP 포트)

Imgur

us-vm1에서 클라이언트 모드로 실행 (UDP)

$ iperf -c eu-vm -u -b 2G #iperf client side - send 2 Gbit/s

Imgur

위에서 측정한 네트워크 성능을 보면 TCP보다 UDP가 더 빠름을 알수 있습니다.

eu-vm에서 서버 모드로 실행

$ iperf -s

us-vm1에서 클라이언트 모드로 실행

-P number of parallel client threads to run

$ iperf -c eu-vm -P 20

Imgur

위의 성능 측정결과를 보면 Bandwith의 합이 달성 가능한 최대 Bandwith에 근접한 것을 알수 있다.

Interactive하게 tcpdump 실행 
$ sudo tcpdump -c 1000 -i eth0 not tcp port 22

옵션
-c : 카운트 1000개를 보여줌
-i : 모니터링 하고자 하는 interface 이름, 여기서는 eth0에서 들어오는 패킷의 정보를 보여준다.

us-vm1에서 apache 웹서버를 설치 후 tcpdump를 실행합니다.

$ sudo apt-get -y install apache2

$ sudo tcpdump -i eth0 -c 1000 -s 1460 -w webserver.pcap tcp port 80

옵션
-s 1460 : 단지 header 만이 아니라 모든 패킷을 수집
-w 파일명 : 수집한 패킷을 지정한 파일에 저장

us-vm2에서 curl 명령으로 apache 서버에 접속합니다.

$ curl us-vm1
$ curl us-vm1/404.php
Packet capture 파일인 webserver.pcap 분석
$ sudo tcpdump -nr webserver.pcap

단지 protocol, source 그리고 destination 정보를 보여준다. Imgur

CloudShark 이용하여 분석하기

해당 project를 설정하고 저장된 Packet capture 파일을 복사합니다.

$ gcloud config set project <your-project-name> #only if not done before
$ gcloud compute copy-files us-vm1:~/webserver.pcap webserver.pcap --zone us-central1-f

노트북에 Google Cloud SDK가 설치되어 있지 않다면 Google Storage에 저장합니다.

$ gcloud compute copy-files us-vm1:~/webserver.pcap webserver.pcap --zone us-central1-f

Imgur

$ gsutil mb gs://username-lab #replace username with a unique username
$ gsutil cp webserver.pcap gs://username-lab/

Imgur

CloudShark를 통해 분석합니다. Imgur Imgur

Basic firewalling and load balancing
방화벽 추가

us-vmc에 nginx 설치 후에 81번 포트에 응답하도록 설정한다.

$ sudo su - 
# apt-get -y install nginx
# echo "server { listen 81; root /usr/share/nginx/html; }" > /etc/nginx/sites-enabled/default
# service nginx restart
# curl localhost:81
# exit
$

81번 포트에 대한 방화벽 룰 추가

  • us-vmc 인스턴스에 대하여 nginx-81이라는 태그를 추가합니다.
  • nginx-81이라는 방화벽 룰을 생성합니다.
$ gcloud compute instances add-tags us-vmc --tags nginx-81 --zone us-central1-c
$ gcloud compute firewall-rules create nginx-81 --allow tcp:81 --network codelab --source-ranges 0.0.0.0/0 --target-tags nginx-81
Test Network Load Balancer 1/3

각각의 instance에 apache webserver를 설치하는 스크립트를 실행합니다.

Debian

for a in us-vm1 us-vmc eu-vm asia-vm ; do  
  gcloud compute ssh --command "sudo apt-get -y install apache2" --zone `gcloud compute instances list $a --format text | grep zone: | awk '{print $2}'` $a; 
done  

CentOS

gcloud compute ssh --ssh-flag="-t" --command "sudo yum -y install httpd; sudo service httpd start" --zone us-central1-f us-vm2  

CentOS의 경우 apache DocumentRoot로 되어 있는 /var/www/html(비어있음)에 새로운 index.html을 만들지 않으면 /usr/share/httpd/noindex/index.html이 로드됩니다.
문제는 load balancer에서 아래와 같이 오류로 인식한다 Imgur

오류를 해결하려면 /var/www/html에 index.html을 만듭니다.

codelab 네트워크에 있는 VM에서 아래 명령어 실행합니다.

for a in us-vm1 us-vm2 us-vmc eu-vm asia-vm ; do curl $a; done  
US loadbalancer 생성

80 포트에 대하여 방화벽을 오픈합니다.

$ gcloud compute firewall-rules create http --allow tcp:80 --network codelab

load balancer 설정

  • http healthy 체크 : Path / 에 대하여 80 포트 헬스 체크
  • load balancer는 하나의 region(여기서는 US)에 있는 인스턴스들의 target-pool로 구성됩니다. 우선 target-pool을 생성하고 인스턴스를 추가합니다.
  • forwarding-rule을 추가합니다.
$ gcloud compute http-health-checks create basic-check
$ gcloud compute target-pools create apaches --region us-central1 --health-check basic-check
$ gcloud compute target-pools add-instances apaches --instances us-vm1,us-vm2 --zone us-central1-f
$ gcloud compute target-pools add-instances apaches --instances us-vmc --zone us-central1-c
$ gcloud compute forwarding-rules create interwebs --region us-central1 --port-range 80 --target-pool apaches
Test Network Load Balancer 2/3

us-vm1, us-vmc, eu-vm, asia-vm 인스턴스에 대하여 index.html 에 host명을 입력하여 웹 접속 시 호스트명이 표시되게 설정합니다.

$ for a in us-vm1 us-vmc eu-vm asia-vm ; do gcloud compute ssh --command "sudo hostname | sudo tee /var/www/html/index.html > /dev/null" --zone `gcloud compute instances list $a --format text | grep zone: | awk '{print $2}'` $a; done
Test Network Load Balancer 3/3

eu-vm, asia-vm에 대한 target-instance 생성합니다.

$ gcloud compute target-instances create eu-target --instance eu-vm --zone europe-west1-d
$ gcloud compute forwarding-rules create interwebs-eu --region europe-west1 --port-range 80 --target-instance eu-target --target-instance-zone europe-west1-d
$ gcloud compute target-instances create asia-target --instance asia-vm --zone asia-east1-c
$ gcloud compute forwarding-rules create interwebs-asia --region asia-east1 --port-range 80 --target-instance asia-target --target-instance-zone asia-east1-c
Test HTTP Load Balancer

아래 아키텍쳐가 글로벌하게 웹서비스를 구성하는 방법이다. Imgur

요청이 들어와서 instance에 전달되는 순서와 반대로 서비스를 구성하면 됩니다.

  1. Instance Group
  2. Backend Service
  3. URL Map
  4. Target Proxy
  5. Global Forwarding Rule
Instance Group

모든 zone에 대하여 unmanaged instance group(non-autoscaled) instance-groups unmanaged create 을 생성합니다.
생성된 instance group에 해당 zone에 있는 instance를 추가 instance-groups unmanaged add-instances 합니다. instance group에 대하여 named port를 http:80으로 설정 instance-groups unmanaged set-named-ports 합니다.

$ gcloud compute instance-groups unmanaged create us-f --zone us-central1-f
$ gcloud compute instance-groups unmanaged create us-c --zone us-central1-c
$ gcloud compute instance-groups unmanaged create eu --zone europe-west1-d
$ gcloud compute instance-groups unmanaged create asia --zone asia-east1-c
$ gcloud compute instance-groups unmanaged add-instances us-f --instances us-vm1,us-vm2 --zone us-central1-f
$ gcloud compute instance-groups unmanaged add-instances us-c --instances us-vmc --zone us-central1-c
$ gcloud compute instance-groups unmanaged add-instances eu --instances eu-vm --zone europe-west1-d
$ gcloud compute instance-groups unmanaged add-instances asia --instances asia-vm --zone asia-east1-c
$ gcloud compute instance-groups unmanaged set-named-ports us-f --named-ports http:80 --zone us-central1-f
$ gcloud compute instance-groups unmanaged set-named-ports us-c --named-ports http:80 --zone us-central1-c
$ gcloud compute instance-groups unmanaged set-named-ports eu --named-ports http:80 --zone europe-west1-d
$ gcloud compute instance-groups unmanaged set-named-ports asia --named-ports http:80 --zone asia-east1-c
Backend Service

global-bs란 이름의 backend service 를 생성합니다.
backend service에 instance group을 추가합니다.
global-map란 이름의 url-map 생성합니다.

$ gcloud compute backend-services create global-bs --protocol http --http-health-checks basic-check
$ gcloud compute backend-services add-backend global-bs --instance-group us-f --instance-group-zone us-central1-f
$ gcloud compute backend-services add-backend global-bs --instance-group us-c --instance-group-zone us-central1-c
$ gcloud compute backend-services add-backend global-bs --instance-group eu --instance-group-zone europe-west1-d
$ gcloud compute backend-services add-backend global-bs --instance-group asia --instance-group-zone asia-east1-c
$ gcloud compute url-maps create global-map --default-service global-bs
URL Map

요청이 load balancer로 들어올때 URL Map의 설정에 따라 backend로 라우팅을 합니다.
이때 URL Map은 목적지의 URL에 있는 host값(example.com)과 path값(/path)을 가지고 그 요청에 해당되는 적절한 backend service로 전달합니다. Imgur Imgur
아래 그림은 실제로 요청에 포함된 path 값에 따라 어떻게 backend service로 전달되는지 알수 있습니다. Imgur

요청에 포함된 특정 path와 backend service를 연결하는 방법은 아래와 같습니다.

gcloud compute url-maps add-path-matcher URL_MAP \  
    --default-service BACKEND_SERVICE \
    --path-matcher-name PATH_MATCHER \
    [--path-rules PATH=SERVICE]
--path-rules /video=video-service,/video/*=video-service
https://cloud.google.com/compute/docs/load-balancing/http/url-map  
target proxy

global-proxy란 이름의 target proxy 를 생성하고 GLOBAL IP에 대하여 forwarding rule을 설정합니다.
target proxy는 하나 이상의 global forwarding rule을 참조하여 들어오는 HTTP와 HTTPS 요청을 URL Map으로 라우팅한다.

gcloud compute target-http-proxies create [HTTP_PROXY] \  
 — url-map URL_MAP [ — description [DESCRIPTION]]
gcloud compute target-https-proxies create [HTTPS_PROXY] \  
 — url-map URL_MAP — ssl-certificate [SSL_CERTIFICATES] \
 [ — description [DESCRIPTION]]
$ gcloud compute target-http-proxies create global-proxy --url-map global-map
$ gcloud compute forwarding-rules create global-lb --global --target-http-proxy global-proxy --ports 80
Global forwarding rules

global forwarding rule은 서비스하는 site의 DNS Record에 사용할 수 있는 global IP address 하나를 제공합니다. 또한 target proxy와 URL map의 load balancing 설정에 포함된 IP address, port, and protocol 등을 통해 instance group으로 라우팅합니다.
Global forwarding rule은 단지 HTTP/HTTPS load balancer에만 사용할 수 있고 하나의 global forwarding rule은 하나의 포트로만 전달할 수 있습니다.

gcloud compute forwarding-rules create  
 FORWARDING_RULE — global
 [ — address ADDRESS]
 [ — description DESCRIPTION]
 [ — ip-protocol IP_PROTOCOL]
 [ — port-range PORT]
 [ — target-http-proxy TARGET_HTTP_PROXY | — target-https-proxy TARGET_HTTPS_PROXY ]

Imgur Imgur Imgur Imgur

apache 로그 설정 변경

apache의 access.log를 확인합니다.

$ tail -10 /var/log/apache2/access.log

130.211.1.214 — — [30/Sep/2015:11:08:28 +0000] “GET / HTTP/1.1” 200 316 “-” “GoogleHC/1.0”

Debian VMs (all VMs but us-vm2)

$ sed -e 's/%h/%{X-Forwarded-For}i/' /etc/apache2/apache2.conf | sudo tee /etc/apache2/apache2.conf > /dev/null
$ sudo service apache2 reload

CentOS VM (us-vm2)

$ sudo sed -e 's/%h/%{X-Forwarded-For}i/' /etc/httpd/conf/httpd.conf | sudo tee /etc/httpd/conf/httpd.conf > /dev/null
$ sudo service httpd reload

 HTTPS load balancer 테스트

self-signed certificate 생성

  • generate a private key
  • generate a signing request for the public certificate matching the key
  • sign the request using the key we just created
$ mkdir ssl
$ cd ssl
$ openssl genrsa -out my.key 2048
$ openssl req -new -key my.key -out my.csr #Enter data at each prompt except PW
$ openssl x509 -req -days 365 -in my.csr -signkey my.key -out my.crt

ssl certificate 생성

$ sudo gcloud compute ssl-certificates create ssl --certificate my.crt --private-key my.key

target https proxy와 forwarding rule 생성

$ gcloud compute target-https-proxies create ssl-proxy --url-map global-map --ssl-certificate ssl
$ gcloud compute forwarding-rules create ssl-lb --global --target-https-proxy ssl-proxy --port 443
테스트

eu-vm에 접속하여 아래 명령으로 접속 시 가장 가까운 eu-vm으로 접속합니다.

curl Global external IP address  

아래와 같이 eu-vm으로만 연결되고 있습니다. Imgur

eu-vm의 apache 웹서버를 종료하고 다시 접속을 해봅니다.
아래와 같이 asia-vm, us-vm1, us-vm2 로 골고루 접속되는 것을 알수 있다. 지리적인 위치가 asia와 us가 비슷한 듯 보인다. Imgur

TCP keepalive settings

GCP firewall은 connection table에 단지 10분동안 idle TCP connection을 유지합니다.
다시 말하면 10분안에 패킷이 들어오거나 나가는 패킷이 없다면 firewall에서 session이 제거됩니다. Compute Engine instance에 ssh로 접속하고 10분동안 어떤 작업도 하지 않는다면 10분 후에는 GCP firewall에서 연결을 끊어버리고 터미널은 hang이 걸리게 됩니다.
아래 설정은 TCP keepalive을 정기적으로 (1분) 세션을 유지 할수 있도록 설정을 변경합니다.

sudo /sbin/sysctl -w net.ipv4.tcp_keepalive_time=60 net.ipv4.tcp_keepalive_intvl=60 net.ipv4.tcp_keepalive_probes=5  

Martin

Read more posts by this author.