Terraform 오버뷰 - GCP Cloud Run 배포하기 공부/CLOUD

Date 2021. 8. 16. 16:29

테라폼이란

클라우드의 인프라를 선언적(declaritve)으로 관리할 수 있게 해주는 IaC(Infrastructur as Code) 오픈소스 소프트웨어이다.

 

다시 풀어서 말하면 클라우드의 리소스(EC2의 경우 ami, instance type, GCP Cloud Run의 경우 컨테이너의 spec 등..)을

1) 선언적 2) 소스코드로 관리 할수 있는 소프트웨어라 할 수 있다.

 

이러한 IaC 툴을 이용하면 기존에 리소스를 CLI/ 콘솔 등으로 관리할때 보다 다양한 장점을 가져갈 수 있다.

 

1) 기존 방식인 콘솔 또는 CLI(API call) 을 통해 클라우드 리소스에 접근하는거와 달리 Code로 관리함으로써 클라우드 인프라에 대한 버전관리를 할 수 있다.(git 등 이용)

2) 코드로 관리하기 때문에 같은 인프라를 여러번 복제 하는 등 쉽게 인프라를 배포할 수 있다.

 

리소스 배포하기

가장 먼저 클라우드 리소스에 접근할 수 있는 API Key가 필요하다. GCP를 사용했고 json 형식의 키를 발급받아 사용했다.

1) Configuration

우선 테라폼 CLI를 설치해야 한다. 단일 바이너리 파일로 설치되므로 편리하다.

 

sudo apt-get update && sudo apt-get install -y gnupg software-properties-common curl

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -

sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"

sudo apt-get update && sudo apt-get install terraform

 

다음은 테라폼에 대한 Configuration을 해주어야 한다. 폴더를 생성하고 key file을 가져온 뒤 main.tf를 수정한다.

 

cd terraform
cp JSON_KEY ./key.json

vi main.tf

terraform {
  required_providers {
    google = {
      source = "hashicorp/google"
      version = "3.5.0"
    }
  }
}

provider "google" {
  credentials = file("key.json")

  project = "PROJECT"
  region  = "REGION"
  zone    = "ZONE"
}

GCP를 기준으로 했으며 PROJECT, REGION, ZONE을 적절히 입력한다.

 

이제 테라폼 CLI를 이용해 프로젝트를 초기화한다.

 

terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/google from the dependency lock file
- Installing hashicorp/google v3.5.0...
- Installed hashicorp/google v3.5.0 (signed by HashiCorp)

 

2) Write

이제 배포할 리소스에 대한 선언이 필요하다. 간단한 Cloud Run 컨테이너를 배포한다.

 

vi cloudrun.tf

resource "google_cloud_run_service" "default" {
  name     = "cloudrun-srv"
  location = "asia-northeast1"

  template {
    spec {
      containers {
        image = "us-docker.pkg.dev/cloudrun/container/hello"
      }
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }
}

 

Terraform Registry 에서 배포 가능한 리소스들의 정보를 알 수 있다.

 

3) Apply

terraform apply를 통해 기존 state와 리소스들을 비교하며 업데이트를 수행한다.

 

terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

...

 

4) 결과 확인

 

terraform show 명령어는 현재 state를 보여준다. 

 

terraform show

resource "google_cloud_run_service" ...

terraform show | grep url

url = "https://cloudrun-srv-ㅁㅁ-an.a.run.app"

// 컨테이너 cold start로 응답 지연될 수 있음
// IAM Policy를 설정해주지 않아 Forbidden을 반환합니다.
curl https://cloudrun-srv-ㅁㅁ-an.a.run.app
...

 

쓰면서 느낀 점

일단 쉽게 리소스를 배포할 수 있다는 뚜렷한 장점이 있다. 또한 테라폼 공식 페이지가 굉장히 잘나와있고 레퍼런스가 많아 참고할 자료가 많다.

 

반면에 불편한 점들도 존재한다.

기존에 있던 리소스를 테라폼으로 관리하기 위해서는 terraform import 를 통해 불러와야 하는데,

 

state만 업데이트 하고 configuration은 관리해주지 않는다. 손으로 한땀한땀 tf 파일을 수정해줘야 한다.

이를 위해 terraforming이나 terraformer 등의 도구가 존재하지만 완벽하지는 않아서 직접 수정해야 할 필요가 있다.

 

또한 테라폼 자체의 단점은 아니지만 테라폼으로 생성한 리소스를 기존 방식인 CLI등으로 수정하면 당연히 state와 어긋나게 된다. 이를 맞추려면 terraform taint나 terraform apply -replace를 통해 state를 맞춰줘야 할 필요가 있다.

[k8s] Service 리소스 Overview (2) : Ingress와 Health check 공부/CLOUD

Date 2021. 8. 15. 17:34

저번 글에 이어 Ingress와 Health check를 정리했다.

Ingress

  • 쿠버네티스 Ingress 리소스를 통해 HTTP 트래픽을 여러 Service 로 전달할 수 있다.
  • 우선 실제로 트래픽을 보고 처리해야 하는 Ingress Controller 가 필요하다. 대표적으로 오픈소스 웹서버인 nginx 구현체인 Nginx Ingress Controller 가 존재한다.
  • https://kubernetes.io/ko/docs/concepts/services-networking/ingress-controllers/
    • 구글의 쿠버네티스 서비스인 GKE 는 자체적으로 구현한 ingress-gce 가 존재한다.
  • 접근하는 트래픽에 대해 어떻게 처리할지에 대해서 관리하는게 Ingress 리소스이다.
 

인그레스 컨트롤러

인그레스 리소스가 작동하려면, 클러스터는 실행 중인 인그레스 컨트롤러가 반드시 필요하다. kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 다른 타입과 달리 인그레스 컨트롤러

kubernetes.io

 

  • metadataannotations 를 이용해 인그레스 오브젝트에 대한 옵션을 설정할 수 있다.
    • nginx 의 경우 nginx.ingress.kubernetes.io/rewrite-target 같은 옵션이 존재한다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-test
  annotations:
  ...
spec:
  rules:
    - host: test.example.com
    http:
        paths:
        - path: /test
            backend:
                service:
                    name: test
                    port:
                        number: 80

 

  • Ingress 리소스의 경우 Ingress Controller 가 받는 트래픽 중
    • 요청의 Host 헤더가 test.example.com 인 요청에 대해 test 서비스의 80 포트로 보내진다.
  • 하나의 Ingress 에 다양한 rulespath 를 사용할 수 있다.
    • GCP 에서 사용하는 Cloud Load Balacerurl map 이란 리소스가 해당 역할을 담당한다.
      • ingress-gce 레포에 pkg/loadbalancer/url_maps 로 확인할 수 있다.

Ingress TLS

  • Ingress Controller 는 HTTPS 트래픽을 받아 TLS Connection 을 열고 백엔드에 위치한 서비스들에는 HTTP 트래픽으로 전송한다.(Terminate TLS)
  • TLS 연결에 사용되는 서버 인증서는 발급받은 뒤 Secret 리소스를 사용하여 저장할 수 있다.
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj \
CN=test.example.com

kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key

 

  • 또는 CSR 을 생성해서 CertificateSigningRequest 리소스를 통해 발급받아도 된다고 한다.
kind: Ingress
...
spec:
    tls:
    - hosts: 
        - test.example.com
        secretName: tls-secret
...

 

annotationnginx.gress.kubernetes.io/ssl-redirect 기본값은 True 다. 즉 HTTP 로 요청을 보내도 tls 가 존재하면 HTTPS 로 리다이렉트한다.

Health check

  • ServicelabelSelector 에 맞는 Pod 들은 자동으로 서비스의 Endpoint 리소스로 등록된다. 하지만 Pod 가 생성된 뒤 Configuration이 필요하거나 등의 warm-up 절차가 있다면 Service 는 해당 Pod 로 요청을 보내서는 안될것이다. 이를 위해 Readiness Probe가 존재한다.

Readiness Probes

  • Pod 가 클라이언트의 요청을 받아들일 수 있는지 확인하기 위해 존재한다.
  • 주기적으로 호출되어 Pod 가 요청을 받을 수 있는지 확인한다.
  • Container 마다 요청을 받을 수 있다는 상태는 다르다. 쿠버네티스는 3가지 종류를 지원한다.
    • HTTP GET probe : 요청을 보내 HTTP Status code를 보고 확인한다.
    • TCP Socket : 컨테이너의 특정 port로 소켓을 오픈한다. Established 면 Ready 상태.
    • Exec probe : 컨테이너에서 프로세스를 실행해 Exit status code를 참조한다.
  • Liveness Probe 와 달리 실패해도 Pod를 재시작하지는 않는다.

[k8s] Service 리소스 Overview (1) 공부/CLOUD

Date 2021. 8. 14. 19:26

클러스터 내부에서든 외부에서든 실제 Workload를 받는 부분인 Pod에 접근하기 위해서는 Pod의 IP정보+ port를 알아야 한다.

 

Replication Controller가 조정할 수도 있고 Node가 죽어서 다른 Node 로 파드를 옮기는 등 쿠버네티스에서 Pod라는 리소스는 항상 죽을 수 있다. 즉 Pod를 식별하는 IP는 계속 변경된다.

 

이런 문제를 해결하기 위해서 Pod에 접근하는 고정된 IP가 필요한데, 이를 담당하는 오브젝트가 바로 Service 이다.

 

서비스는 리소스가 살아있는 한 고정된 IP를 가지고 있으며, TCP/UDP 패킷을 Pod로 Redirect 해준다.

Service의 작동방식

우선 어떤 Pod로 트래픽을 분산할지 Pod를 찾아야 한다. Pod를 찾는 방법은 labelSelector가 있다. (다른 방법이 있을 수 있음~?)

 

우선 해당 Selector를 만족하는 Pod들을 찾는다. 또한 그 Pod의 IP를 이용해 Endpoint 리소스(IP:ContainerPort)를 생성한다.

 

EndPoint 리소스들은 서비스에 붙게되며, 클러스터 내부의 클라이언트가 해당 서비스에 요청을 보내면 서비스는 해당하는 Endpoint 중 하나로 트래픽을 redirect 하게 된다.

 

  • 만약 Pod가 요청에 대한 세션을 가지고 있어야 한다면 sessionAffinity 를 사용할 수 있다. 이를 통해 요청은 계속해서 동일한 Pod로 전달된다.
  • Service는 TCP/UDP 트래픽을 분산하므로 HTTP 메시지를 볼 수 없다. ( 따라서 Cookie 값을 보고 로드밸런싱 한다던지의 기능을 수행할 수 없다. )
  • 여러개의 Port를 서비스에 연결할 수 있다.
  • targetPort로 숫자 이외의 http,https 등 alias 등을 사용할 수 있다. 이렇게 사용하면 Pod의 포트가 변경되어도 서비스를 수정할 필요가 없다.

Discovering Service

클러스터 내부에서 Service로 요청을 보내려면 해당 Service의 IP를 알아야 한다. 어떻게 알아야 할까?

  1. ENV
    1. 파드가 실행되면 환경변수 값들로 서비스의 IP와 포트가 들어간다. 가장 처음 존재하는 쿠버네티스 서비스의 경우
KUBERNETES_SERVICE_HOST= ... 
KUBERNETES_SERVICE_PORT= ...

로 파드 컨테이너의 환경변수로 들어간다.

 

  1. DNS
    1. 내부 DNS 서버인 kube-dns를 이용한다. 해당 DNS 서버에 서비스의 FQDN을 쿼리함으로써 서비스의 IP를 찾을 수 있다.

Service outside the cluster

Pod가 클러스터 외부 리소스에 접근할 때도 Service 리소스를 사용할 수 있다. externalName 타입의 서비스로 클러스터 외부의 도메인을 등록함으로써 서비스의 FQDN을 통해 클러스터 외부의 서비스에 접근할 수 있다.

 

Service를 클러스터 외부에 노출하기

 

클러스터 외부의 클라이언트가 Service에 요청을 보내기 위해서는 다양한 방식이 존재한다.

 

  1. NodePort
    1. 말 그대로 (워커)Node의 Port를 오픈한다. 해당 NodeIP:Port로 요청을 보내면 NodePort서비스는 Pod로 트래픽을 redirect 한다.
    2. 서비스에 dedicated한 Node의 Port를 할당한다. 해당 서비스로 트래픽을 보내려면 두가지 방법이 존재한다. 
    3. SERVICE_IP:PORT, nth NODE IP:NODEPORT
    4. SERVICE_IP의 경우 클러스터 내부 IP이고, 클러스터 외부에서는 NODE의 IP를 통해 접근할 수 있다.(물론 인바운드 NODEPORT에 대한 트래픽을 받아야 한다.)
    5. 이 방법의 경우 특정 노드가 죽어버리면 그 IP를 통해서는 더이상 트래픽을 받지 못한다는 단점이 있다.
  1. LoadBalancer
    1. Kubernetes Cloud Provider들이 제공해주는 LoadBalancer 리소스를 통해 dedicated IP로 트래픽을 받아 NodePort로 트래픽을 redirect한다.
    2. public하게 접근가능한 IP를 할당한다. 내부적으로는 NodePort서비스로 구현된다.
    3. LB의 IP:PORT로 접근 시 특정 NodePort로 연결한다. 해당 NodePort는 또 Pod로 트래픽을 분산한다.(implicitly assigned Nodeport)
  1. Ingress
  • 주로 HTTP 패킷을 받아 여러 서비스로 패킷을 전달한다. (다음 글에서 설명)

 

Peculiarities of External Connection

  1. 불필요한 Network hops
    1. 외부에서 Pod로 트래픽을 보내려면 LB -> NodePort -> Pod를 거친다. 여기서 Node에 Pod가 존재할 수도 있고 없으면 다른 Node로 보낼 수도 있는데, 이는 불필요한 hop수를 증가시킨다.
    2. Service 오브젝트의 스펙에 externalTrafficPolicy: local 을 명시하면 해당 Node에 존재하는 파드로만 트래픽을 분산한다. ( 이 경우 해당 Node에 실행중인 Pod가 없다면 hanging된다. 또한 트래픽을 불균등하게 받을 수 있다.. 특정 Node에 실행중인 Pod가 많으면)

 

  1. Client IP를 잃어버린다.
    1. Nodeport 서비스의 경우 SNAT해서 원래의 IP를 잃어버리고 Pod에 트래픽이 도달한다.

 

References

Service, Kubernetes up & running

JWT(Json Web Token)이란 공부/BE, DB

Date 2021. 7. 30. 14:52

JWT란 서비스와 서비스 간 통신 시 인증(Authentication)과 인가(Authorization)에 주로 사용하는 토큰이다.

 

요청을 하는 서비스는 JWT를 포함하여 요청을 전송하고, 요청을 받아들이는 서버는 이 JWT를 보고 해당 요청을 허가하거나 거부한다.(Authorization)

 

JWT RFC문서를 살펴보면(rfc7519) 'The JWT conform to either the JWS or JWE specification' 이라고 적혀있다.

즉 JWS 또는 JWE Spec을 구현한 것이 JWT라고 할 수 있다.

 

여기서 우리가 살펴볼 것은 대부분 JWT 구현에 사용하는 Header, Payload, Signature로 구성되는 JWS Specification이다.

 

JWS로 구현한 JWT의 정의를 살펴보자면,

1. URL-safe 하다. 즉 HTTP Request에 JWT를 포함할 시 요청의 URL(path) 부분에도 넣어도 상관이 없다는 뜻이다.

2. 총 3개의 부분 : Header, Payload, Signature로 구성되고, 각 세 부분을 '.'로 구분한다.

3. Header와 Payload는 JSON 객체를 BASE64url 인코딩한 문자열이다.

4. key:value 쌍을 claim이라 하고 a set of claims를 JSON 객체로 표현한다.

 

 

JWT 생성하기, JWT 검증하기, JWT 사용 사례 크게 세 부분으로 나누어 설명하겠다.

JWT 생성하기

Payload

일단 정보를 담을 Payload를 만들어야 한다. 이 Payload는 a set of claims을 JSON 형태로 나타낸 뒤 URL-safe 하게 BASE64url 인코딩 한 것이다.

claim의 key는 string이어야 하고 value는 JSON value여야 한다. 이 조건을 만족시키면 claim이 될 수 있다.

 

IANA(Internet Assigned Numbers Authority)에 가면 자주 사용하는 payload claim들이 나열되어 있다.

 

대표적으로 iss(issuer), sub(subject), exp(expiration) 등이 존재한다. 이외에도 필요한 정보를 Payload에 claim 형태로 담을 수 있다.

{
  "iss": "donghyeong",
  "sub": "intro"
}

 

위와 같은 JSON을 BASE64url 인코딩하면 Payload가 완성된다.

 

ewogICJpc3MiOiAiZG9uZ2h5ZW9uZyIsCgkic3ViIjogImludHJvIgp9

Header

 

헤더는 JOSE(JSON Object Signing and Encryption) 헤더라고 한다. 즉 이 JWT 토큰이 무결(integrity)한지 확인하기 위한 메타데이터들을 담고 있다. 자세한 정보는 마찬가지로 IANA 에서 확인할 수 있다.

 

가장 중요한 claim은 alg로, 나중에 Signature를 생성하고 검증할 때 사용한다. 자세한 내용은 뒷부분에서 설명하겠다.

 

{
  "alg": "HS256"
}

 

마찬가지로 위와 같은 JSON을 BASE64url 인코딩하면 Header가 완성된다.

 

eyJhbGciOiJIUzI1NiJ9

Signature

 

JWT의 Header와 Payload는 단순히 BASE64url 인코딩한 것이기 때문에 누구나 읽거나 수정할 수 있다. 이러한 정보들이 변조되지 않았음을 증명하기 위해 서명(Signature)를 이용한다.

 

Header와 Payload를 이어붙인 값에 헤더의 알고리즘을 이용해 서명(Signature) 한다.

 

SIGNATURE = BASE64url(ALGORITHM(Header + '.' + Payload, Private Key))

 

이러한 서명 알고리즘에는 대표적으로 SHA등 HMAC으로 대표되는 대칭키 알고리즘,

비대칭키를 사용하는 알고리즘 등이 존재한다.

 

"구글 계정으로 로그인" 등 OpenID Connect에서는 비대칭키를 사용하는 JWT를 사용한다고 한다.

구글같은 ID-Provider는 구글의 Private key로 토큰을 서명하고, "구글 계정으로 로그인" 등 기능을 사용하는 App은 구글의 Public key로 해당 토큰을 검증하여 Integrity를 확인한다.

 

본론으로 돌아와 이렇게 생성된 Signature를 Header와 Payload에 이어붙이면 JWT가 완성된다.

 

JWT = HEADER.PAYLOAD.SIGNATURE

JWT 검증하기

 

이렇게 생성된 JWT가 변조되지 않았음을 확인하기 위해서는 Signature를 이용해 검증하게 된다.

Key(비대칭 알고리즘의 경우 Public Key)를 알고 있다고 가정하고 Header와 Payload의 값을 헤더의 알고리즘으로 계산한 결과가 Signature와 같으면 Validate하다고 판단한다.

 

ALGORITHM(HEADER + '.' + PAYLOAD, Key) === BASE64urlDecode(SIGNATURE)

JWT 사용 사례

API Key

JWT를 API Key로 사용해 클라이언트는 JWT를 포함하여 요청하고, 서버는 해당 JWT를 보고 해당 요청을 받아들일지 거부할지 선택한다.

  1. 클라이언트는 서버에게 JWT를 제공받는다. ( 로그인 등 )
  2. API Call시 HTTP 요청에 JWT를 담아 ( 보통 Authorization Header ) 전송한다.
  3. 서버는 해당 JWT를 검증하고 Payload에 담은 값을 바탕으로 API요청을 처리하거나 거부한다.

OAuth

인증/인가 관련 표준인 OAuth2.0에서도 토큰으로 JWT를 사용할 수 있다.

 

 

 

[Container] Container와 VM 공부/OTHERS

Date 2021. 5. 27. 16:23

두 기술 모두 프로그램을 독립적으로 실행하기 위해 사용한다. 이는 하드웨어 자원을 효율적으로 쓸 수 있게 해준다.

VM

VM(Virtual Machine) 은 Hypervisor 라는 소프트웨어 위에서 관리된다.
Hypervisor가 호스트와 VM 사이에서 중간 관리자 역할을 하며 VM을 생성 및 관리하고 시스템 콜등을 실행한다.
이 때 Hypervisor 위에서 돌아가는 OS를 Guest OS라 하며 Guest OS > Hypervisor >( Host OS ) > Hardware 구조로 구성되게 된다.

 

크게 Type1과 Type2가 있는데,

Type1 Hypervisor는 Native 방식이라 하여 하드웨어 위에서 바로 실행되며 하이퍼바이저가 바로 하드웨어를 제어하게 된다. 직접 하드웨어를 제어하므로 Type2에 비해 오버헤드가 적다. 대표적으로 Xen, 리눅스의 KVM 등이 존재한다.

 

Type2 Hypervisor는 호스트 하이퍼바이저라고 불리며 하드웨어 -> Host OS -> Hypervisor 구조로 구성되어 중간 다리 역할을 해준다. 하드웨어 리소스에 접근하기 위해 Host OS에 요청해야 하므로 오버헤드가 있다.

 

AWS EC2는 Xen Hypervisor 와 AWS Nitro Hypervisor를  사용한다고 한다. 

Container

상대적으로 가벼운 가상화 방법으로, 같은 호스트 위에서 프로세스를 격리한다.
호스트 위에서 커널을 공유하므로 거의 0에 가까운 오버헤드를 가지며 프로세스를 격리된 환경에서 실행할 수 있게 해준다.

 

이는 리눅스 커널에 내장된 namespacecgroups 기능을 이용해서 구현될 수 있다.

 

먼저 namespace는 호스트에서 독립된 제한된 공간을 할당해주는 기능으로,

총 6개의 네임스페이스( mount, pid, network, ipc, uts, uid) 가 존재한다.

 

두번째로 cgroups는 하드웨어 리소스에 대해 제어를 가능하게 해준다. 메모리, CPU , I/O 등을 제어해 프로세스에 할당해 줄 수 있다.

 

두개의 리눅스 기술을 이용하여 컨테이너를 구현할 수 있고 컨테이너를 통해 프로세스가 실행되는 환경 종속성을 없애줄 수 있다.

'공부 > OTHERS' 카테고리의 다른 글

[Docker] 도커의 네트워크 네임스페이스  (0) 2021.05.26
[Linux] 네트워크 네임스페이스, veth  (0) 2021.05.25

[Docker] 도커의 네트워크 네임스페이스 공부/OTHERS

Date 2021. 5. 26. 21:25

1. 도커의 네트워크 디바이스

도커의 네트워크는 기본적으로 docker0라는 가상 Bridge를 중심으로 구성된다.
이외에도 호스트 네트워크를 사용하는 host, 그리고 null 즉 네트워크 없이 구성할 수도 있다.

 

2. 컨테이너 생성 시 네트워크

먼저 생성된 컨테이너는 veth 쌍을 할당받는다. 하나는 eth0 (컨테이너용), 또하나는 vethXXX로 이름이 붙여지고 docker0 브릿지에 붙는 peer이다.

이렇게 구성함으로써 컨테이너(eth0) - 호스트(vethXXX) - 브릿지(docker0) 형태로 구성되어 패킷이 오갈 수 있는 통로를 만들어준다.

컨테이너 두개를 생성하여 veth pair가 두개 생성되어 호스트에 붙은 상태다.

 


보다시피 master가 docker0으로 되어있다.

또한 여기서 컨테이너 내부에서는 route 경로로 172.0.0.1(docker0) 가 설정된 것을 볼 수 있는데 이는 컨테이너에서 나가는 패킷들은 모두 docker0으로 향하게 한다.

마지막으로 호스트에서는, docker0 브릿지로 FORWARD 되는 패킷들을 모두 ACCEPT 하여 컨테이너와 외부 간 통신이 가능하게 해준다.

 

이를 통해 컨테이너간, 또 컨테이너와 외부 간 네트워크 통신을 가능하게 해준다.

'공부 > OTHERS' 카테고리의 다른 글

[Container] Container와 VM  (0) 2021.05.27
[Linux] 네트워크 네임스페이스, veth  (0) 2021.05.25

[Linux] 네트워크 네임스페이스, veth 공부/OTHERS

Date 2021. 5. 25. 22:40

이 글은 도커 없이 컨테이너 만들기 3편 을 읽고 정리한 글입니다.

1. 네트워크 네임스페이스

리눅스 네임스페이스 중 하나인 네트워크 네임스페이스는 독립적인 네트워크 환경을 구성해 프로세스 간 격리할 수 있는 기술이다.

독립된 네트워크 네임스페이스에서 호스트 디폴트 네임스페이스로 접근할 수 없다. 반대도 마찬가지다. 이를 통해 컨테이너간 네트워크 자원을 분리할 수 있다.
RED 라는 네임스페이스와 BLUE라는 네임스페이스를 생성했다.

네임스페이스들은 모두 /var/run/netns 하위에 생성된다.

 

ip netns add RED
ip netns add BLUE

 

 

2. veth

리눅스의 버추얼 이더넷 인터페이스다. 즉 가상 NIC를 제공해준다. 쌍으로 생성되며 이를 이용해 네트워크 네임스페이스들 간 연결해줄 수 있다.
기본적으로 ip 명령어를 이용해 생성하며 down 상태로 디폴트 네트워크 네임스페이스에 존재하게 된다.

veth0veth1 두개의 쌍을 생성한다.

 

ip link add veth0 type veth peer name veth1

3. 패킷 전송하기

생성된 두 NIC를 각각 RED, BLUE 네임스페이스에 붙인다.

ip link set veth0 netns RED
ip link set veth1 netns BLUE

 

두 디바이스를 활성화 해주고 IP 주소를 할당해준다.

ip netns exec RED ip link set veth0 up ; ip netns exec RED ip addr 11.11.11.2/24 dev veth0
ip netns exec BLUE ip link set veth1 up ; ip netns exec BLUE ip addr 11.11.11.3/24 dev veth1

 

nsenter 커맨드를 이용해 네임스페이스에 진입할 수 있다. RED 네임스페이스에 진입해 아이피 주소 할당을 확인할 수 있다.

nsenter --net=/var/run/netns/RED
ip addr show

 

루프백 과 veth0에 할당된 아이피를 확인할 수 있다.

 

두 네임스페이스 모두 초기 상태이기 때문에 ARP Table, Routing Table 모두 비어있음을 알 수 있다.

ip neighbour show
// ARP table 

ip route show
// route table

 

여기서 RED -> BLUE로 패킷을 보내면 ARP Request 해서 BLUE의 MAC address 찾고 패킷을 전송할 것이다. 확인해 보자.

BLUE Terminal

tcpdump -i veth1

RED Terminal

ping 11.11.11.3

ARP Request -> Response, 그리고 ICMP 로 echo가 왔다갔다 하는것을 볼 수 있다.

 

4. Bridge

 

브릿지는 L2 계층 장비로써 Collision Domain을 쪼개줌으로써 충돌을 줄여준다.
리눅스에서는 가상 브릿지를 만드는 것도 제공해준다.

RED(reth0) - HOST(reth1) - HOST(bridge0) - HOST(beth1) - BLUE(beth0) 형식으로 네트워크를 구성해 RED->BLUE로 패킷을 전송해보겠다.

네임스페이스를 생성하고 디바이스 및 브릿지를 생성해준다.

ip netns add RED
ip link add reth0 type veth peer name reth1
ip link set reth0 netns RED

ip netns add BLUE
ip link add beth0 type veth peer name beth1
ip link set beth0 netns BLUE

ip link add bridge0 type bridge
ip link set reth1 master bridge0
ip link set beth1 master bridge0

 

디바이스들을 모두 turn on 하고 reth0과 beth0에 각각 IP address를 할당해 준다.

ip netns exec RED ip addr add 11.11.11.2/24 dev reth0
ip netns exec BLUE ip addr add 11.11.11.3/24 dev beth0

ip netns exec RED ip link set reth0 up; ip link set reth1 up
ip netns exec BLUE ip link set beth0 up; ip link set beth1 up 
ip link set br0 up

 

위와 마찬가지로 ICMP ping 을 전송한다.

 

HOST Terminal

tcpdump -l -i bridge0

 

BLUE Terminal

tcpdump -l -i beth0

RED Terminal

ping -c 1 11.11.11.3

 

ARP는 수행하지만 패킷이 전송되지 않는다. why ?

이거는 리눅스의 방화벽인 iptables 설정 때문이다.

호스트에 들어오는 모든 패킷들은 netfilter를 보고 룰에 따라 처리한다.

이때 우리가 시도하는것은 reth0 -> beth0 으로 FORWARD ( 외부끼리의 통신, 호스트를 거쳐갈 뿐이고 src dest 모두 외부다. ) 인데

디폴트로 DROP 이다. 따라서 룰 추가를 해줘야 한다.

iptables -t filter -A FORWARD -s 11.11.11.0/24 -j ACCEPT

 

src 가 11.11.11.0/24 인 FORWARD 패킷들은 ACCEPT 한다는 뜻이다.

다시 tcpdump하고 packet 전송 시 성공적으로 ping이 보내지는 것을 알 수 있다.

'공부 > OTHERS' 카테고리의 다른 글

[Container] Container와 VM  (0) 2021.05.27
[Docker] 도커의 네트워크 네임스페이스  (0) 2021.05.26

[GCP] Cloud Run CI/CD 공부/CLOUD

Date 2021. 5. 24. 23:15

1. Cloud Run 이란 ?

Google 에서 제공하는 Serverless 솔루션이다.

AWS의 Lambda 와 유사하지만 Cloud Run은 Container 기반으로, Container 위에서 구동 가능한 것은 뭐든지 실행할 수 있다는 장점이 있다. AWS의 Lambda 에도 컨테이너를 실행할 수 있다.

크게 Managed Cloud Run과 ( 사용중 ) , GKE 위에서 돌아가는 Cloud Run for Anthos가 존재한다.

 

쿠버네티스 위에서 돌아가는 서버리스 솔루션인 Knative를 이용한다고 한다..!

 

어쨌든 사용에 중심을 두고 얘기하자면 다양한 장점이 존재한다.

1. 한번 서비스를 올리고 나면 관리할 포인트가 거의 제로에 가깝다. 알아서 다 해준다. 이런게 서버리스의 장점이다. 

2. 구글의 로깅 및 모니터링 서비스인 Stackdriver를 통해 컨테이너에서 나오는 로그(stdout 등)를 수집하고 관리할 수 있다.  

3. 버전관리가 쉽다. 배포전략을 여러가지로 가져갈 수 있다.(트래픽을 Cloud Run Revision마다 조절할 수 있다.)

4. 그리고 자동으로 HTTPS 엔드포인트도 제공해준다.

 

또한 서버리스 솔루션이지만 최소 인스턴스(컨테이너) 갯수를 남겨둘 수 있다. 이로 인해 Cold Start 문제에 대해 고민할 부분이 적어진다. ( 당연히 요금이 부과된다. )

2. Cloud Run CI/CD 구성

소스코드는 Github 으로 관리하고 있었고, 기존에는 Github Action을 이용해서 GCR(Google Container Registry)로 빌드하는 파이프라인으로 구성하려 했으나,


GCP 내에서도 Build 파이프라인을 구성해주는 Cloud Build란 솔루션이 있어 사용했다. Github Action의 경우 GCP 인증 관련 값들을 관리해줘야 했는데, Cloud Build는 당연히(?) 필요없다.

 

Cloud Build는 서버리스 CI/CD 관리 툴로, 도커 컨테이너에서 실행되는 빌드 단계들로 구성되어 있다.
여기엔 GCP 에서 제공하는 기본적인 이미지들 ( docker, gcloud.. )와 커스텀 빌드 이미지를 사용할 수 있다.

또한 빌드 트리거로 기본적인 Github Push 등 뿐만 아니라 Webhook, Cloud Pub/sub 메시지 등도 제공한다.

나는 간단하게 1. 소스코드 clone후 build 2. 빌드 이미지 GCR에 push 3. Cloud Run에 배포 4. Slack Webhook으로 빌드 알림 순으로 구성했다.  추후 방학때 시간이 되면 테스트도 구성해서 빌드 파이프라인에 포함시킬 예정이다.

Recent Posts

Popular posts

Recent Comments

Tag List

리눅스 알고리즘 클라우드 백준 DNS 네트워크 테라폼 AWS 컨테이너 TypeScript ORM IAC API JWT GCP 인가 인증 k8s DB 네임스페이스 운영체제 도커 JavaScript 파이썬
Total : Today : Yesterday :
Blog powered by Tistory, Designed by hanarotg