인프라/Docker&Kubernetes 2019. 11. 22. 00:01

 

보통 쿠버네티스를 사용하면 단일 클러스터 환경에서 운영하지 않는다. 보통 Phase 별로 클러스터를 구성하기도 하고, 각 Phase의 클러스터는 하나 이상의 노드를 갖는 클러스터 형태인 경우가 많다. 또한 쿠버네티스를 사용하면 하나의 애플리케이션 혹은 미들웨어를 디플로이먼트나 서비스, 컨피그맵 혹은 인그레스 등 여러 종류의 리소스를 조합하는 형태로 배포한다.

 

그런데 각 Phase마다 배포시 달라지는 정보들이 많다. 예를 들면 개발환경의 데이터베이스 주소와 프로덕환경의 데이터베이스 주소가 다른것처럼 말이다. 그렇다면 모든 환경마다 매니페스트를 작성해야하나? 만약 Phase가 많다면 관리가 쉽지 않을 것이다. 이렇게 배포 환경에 따라 달라지는 설정값만 정의해 둔 다음 이에 따라 배포하는 메커니즘이 필요하게 되었는데, 이런 문제를 해결한 것이 헬름(Helm)이다.

 

Helm is a tool for managing Kubernetes charts. Charts are packages of pre-configured Kubernetes resources.
헬름은 쿠버네티스 차트를 관리하기 위한 도구이다. 차트는 사전 구성된 쿠버네티스 리소스의 패키지다.

 

헬름은 패키지 관리 도구고, 차트가 리소스를 하나로 묶은 패키지에 해당한다. 헬름으로 차트를 관리하는 목적은 자칫 번잡해지기 쉬운 매니페스트 파일을 관리하기 쉽게 하기 위한 것이다.

 

실무에서는 로컬 및 운영 클러스터를 막론하고 여러 환경에 배포해야 하는 애플리케이션은 모두 차트로 패키징해 kubectl 대신 헬름으로 배포 및 업데이트를 수행한다. 그 대신 이미 배포된 리소스에 대해 kubectl로 수정한다.

 

헬름설치
> curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh
> chmod 700 get_helm.sh
> ./get_helm.sh

 

필요한 것을 다운로드 받는다.

 

> helm init
Creating /Users/yun-yeoseong/.helm 
Creating /Users/yun-yeoseong/.helm/repository 
Creating /Users/yun-yeoseong/.helm/repository/cache 
Creating /Users/yun-yeoseong/.helm/repository/local 
Creating /Users/yun-yeoseong/.helm/plugins 
Creating /Users/yun-yeoseong/.helm/starters 
Creating /Users/yun-yeoseong/.helm/cache/archive 
Creating /Users/yun-yeoseong/.helm/repository/repositories.yaml 
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com 
Adding local repo with URL: http://127.0.0.1:8879/charts 
$HELM_HOME has been configured at /Users/yun-yeoseong/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation



> kubectl get service,deployment,pod -n kube-system
NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
service/tiller-deploy   ClusterIP   10.96.113.96   <none>        44134/TCP   39s

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/tiller-deploy   1/1     1            1           39s

NAME                                READY   STATUS    RESTARTS   AGE
pod/tiller-deploy-dc4f6cccd-zgvhp   1/1     Running   0          39s

 

여기까지 잘 따라왔다면 설치는 완료된 것이다. 실제로 helm init 명령을 실행하면 틸러라는 서버 애플리케이션이 kube-system 네임스페이스에 배포되고, 틸러는 helm 명령에 따라 설치 등의 작업을 담당하게 된다.

 

현재 사용하고 있는 헬름 버전이 낮다면 아래 명령으로 업그레이드하면 된다.

 

> helm version
> helm init --upgrade //최신버전으로 업그레이드

//특정 버전 헬름 사용
> export TLLER_TAG=2.9.0
> kubectl --namespace=kube-system set image deployments/tiller-deploy tiller=gcr.io/kubernetes-helm/tiller:$TILLER_TAG

 

헬름의 주요 개념

 

헬름은 클라이언트(cli)와 서버(쿠버네티스 클러스터에 설치되는 틸러)로 구성된다. 클라이언트는 서버를 대상으로 명령을 지시하는 역할을 한다. 서버는 클라이언트에서 전달받은 명령에 따라 쿠버네티스 클러스터에 패키지 설치, 업데이트, 삭제 등의 작업을 수행한다.

 

쿠버네티스는 서비스나 디플로이먼트, 인그레스 같은 리소스를 생성하고 매니페스트 파일을 적용하는 방식으로 애플리케이션을 배포한다. 이 매니페스트 파일을 생성하는 템플릿을 여러 개 패키징한 것이 차트다. 차트는 헬름 리포지토리에 tgz 파일로 저장되며, 틸러가 매니페스트를 생성하는 데 사용한다.

 

리포지토리
종류 내용
local 헬름 클라이언트가 설치된 로컬 리포지토리로, 로컬에서 생성한 패키지가 존재한다.
stable 안정 버전에 이른 차트가 존재하는 리포지토리다. 안정된 보안 수준과 기본 설정값을 포함하는 등 일정한 요건을 만족하는 차트만 제공될 수 있다.
incubator stable 요건을 만족하지 못하는 차트가 제공되는 리포지토리다. stable로 넘어갈 예정인 차트가 제공된다.

 

stable 리포지토리는 기본값으로 사용되는 리포지토리로, 깃헙 helm/charts 리포지토리에 저장된 차트를 사용할 수 있다. incubator 리포지토리는 기본값으로 사용되지는 않으나, 다음과 같이 리포지토리를 추가할 수 있다.

 

> helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com/

 

리포지토리에서 다음과 같이 차트를 검색할 수 있다. helm search 명령에 지정한 키워드로 검색도 가능하다.

 

> helm search

 

차트의 구성

차트는 다음과 같은 디렉터리 구성을 갖는다.

 

chart_name
->templates
  ->xxxxx.yaml 각종 쿠버네티스 리소스의 매니페스트 템플릿
  ->_helper.tpl 매니페스트 랜더링에 사용되는 템플릿 헬퍼
  ->NOTE.txt 차트 사용법 등의 참조 문서 템플릿
  ->charts/ 이 차트가 의존하는 차트의 디렉터리
  ->Chart.yaml 차트 정보가 정의된 파일
  ->values.yaml 차트 기본값 value 파일
			

 

차트 설치하기

차트를 이용해 애플리케이션을 설치하려면 helm install 명령을 사용한다. 설치했던 애플리케이션을 업데이트하거나 삭제하려면 릴리스 네임이 필요하므로 --name 옵션으로 릴리스 네임을 붙여준다. 이 릴리스 네임은 해당 클러스터 안에서 유일한 값이어야 한다.

 

> helm install [--name 릴리스_네임] 차트_리포지토리/차트명

 

helm install 명령을 실행하면 차트에 포함된 기본값 value 파일에 정의된 설정값으로 애플리케이션이 설치된다. 그러나 기본값 value 파일을 있는 그대로 사용하는 경우는 드물며, 일부 기본값을 수정한 커스터 value 파일을 주로 사용한다. helm install 예제로 프로젝트 관리 도구인 레드마인의 차트를 이용한다.

 

예제에서는 사용하지 않을 명령 이것은 기본값을 사용하는 일반적인 설치법이다.

> helm install --name redmine-exam stable/redmine
NAME:   redmine-exam
LAST DEPLOYED: Sun Nov 24 17:54:39 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                        AGE
redmine-exam-mariadb        0s
redmine-exam-mariadb-tests  0s

==> v1/Deployment
NAME          AGE
redmine-exam  0s

==> v1/PersistentVolumeClaim
NAME          AGE
redmine-exam  0s

==> v1/Pod(related)
NAME                           AGE
redmine-exam-748d45d8f8-8js7k  0s
redmine-exam-mariadb-0         0s

==> v1/Secret
NAME                  AGE
redmine-exam          0s
redmine-exam-mariadb  0s

==> v1/Service
NAME                  AGE
redmine-exam          0s
redmine-exam-mariadb  0s

==> v1/StatefulSet
NAME                  AGE
redmine-exam-mariadb  0s


NOTES:


1. Get the Redmine URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w redmine-exam'


  export SERVICE_IP=$(kubectl get svc --namespace default redmine-exam --template "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}")
  echo "Redmine URL: http://$SERVICE_IP/"

2. Login with the following credentials

  echo Username: user
  echo Password: $(kubectl get secret --namespace default redmine-exam -o jsonpath="{.data.redmine-password}" | base64 --decode)

 

레드마인 로그인 사용자명과 패스워드를 새로 설정하는 예제를 수행할 것이다. 문서에 규정된 설정값을 따라 커스텀 value 파일을 작성한다. 그리고 다음과 같이 인증정보 설정을 담은 redmine.yaml 파일을 작성한다. 또 인그레스 대신 NodePort 서비스를 사용해 서비스를 노출할 것이므로 serviceType 필드의 값을 NodePort로 수정한다.

 

#redmine.yaml
redmineUsername: yeoseong_gae
redminePassword: yeoseong_gae
redmineLanguage: ja

serviceType: NodePort

 

위 파일을 작성해준다.

 

helm install -f redmine.yaml --name redmine-sample stable/redmine --version 4.0.0
NAME:   redmine-sample
LAST DEPLOYED: Sun Nov 24 18:01:42 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                          AGE
redmine-sample-mariadb        1s
redmine-sample-mariadb-tests  1s

==> v1/PersistentVolumeClaim
NAME                    AGE
redmine-sample-redmine  1s

==> v1/Pod(related)
NAME                                     AGE
redmine-sample-mariadb-0                 1s
redmine-sample-redmine-769df7c8b5-wdgx9  1s

==> v1/Secret
NAME                    AGE
redmine-sample-mariadb  1s
redmine-sample-redmine  1s

==> v1/Service
NAME                    AGE
redmine-sample-mariadb  1s
redmine-sample-redmine  1s

==> v1beta1/Deployment
NAME                    AGE
redmine-sample-redmine  1s

==> v1beta1/StatefulSet
NAME                    AGE
redmine-sample-mariadb  1s


NOTES:
1. Get the Redmine URL:

  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services redmine-sample-redmine)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT/

2. Login with the following credentials

  echo Username: yeoseong_gae
  echo Password: $(kubectl get secret --namespace default redmine-sample-redmine -o jsonpath="{.data.redmine-password}" | base64 --decode)

 

위와 같이 작성한 redmine.yaml 파일을 인자로 포함시켜 레드만을 차트를 설치하였다. 설치가 끝나면 다음과 같이 릴리스 네임의 목록을 확인할 수 있다.

 

> helm ls
NAME          	REVISION	UPDATED                 	STATUS  	CHART        	APP VERSION	NAMESPACE
redmine-sample	1       	Sun Nov 24 18:01:42 2019	DEPLOYED	redmine-4.0.0	3.4.6      	default

 

레드마인 리소스가 생성됐는지 확인한다.

 

> kubectl get service,deployment --selector release=redmine-sample
NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/redmine-sample-mariadb   ClusterIP   10.99.90.57    <none>        3306/TCP       3m1s
service/redmine-sample-redmine   NodePort    10.96.215.91   <none>        80:30441/TCP   3m1s

NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/redmine-sample-redmine   0/1     1            0           3m1s

 

노출하려는 서비스 redmine-sample-redmine이 차트의 기본값 value 파일의 내용대로 LoadBalancer가 아닌 NodePort로 생성되었다. NodePortsms 30441 포트를 개방하고 있으므로 웹브라우저에서 바로 접근가능하다. 그리고 우리가 파일에 작성한 로그인정보로 로그인이 가능하다.

 

헬름으로 설치된 릴리스를 업데이트하려면 다음과 같이 helm upgrade 명령을 사용한다.

 

> helm upgrade -f redmine.yaml redmine stable/redmine --version 4.0.0

 

차트로 설치한 애플리케이션을 제거하고 싶다면 아래 명령을 이용한다,

 

> helm delete 릴리스_네임

 

애플리케이션을 제거해도 헬름에는 롤백 기능이 있기 때문에 원하는 리비전으로 돌아갈 수 있다.

 

> helm ls --all
NAME          	REVISION	UPDATED                 	STATUS  	CHART         	APP VERSION	NAMESPACE
redmine-exam  	1       	Sun Nov 24 17:54:39 2019	DELETED 	redmine-13.5.0	4.0.5      	default

> helm rollback redmine-exam 1

 

만약 리비전 기록을 남기지 않고 애플리케이션을 완전히 제거하려면 다음과 같이 한다.

 

> helm del --purge redmine(릴리즈_네임)

 

사용자 차트 생성하기

사용자 차트를 만들고 이 차트를 사용해 애플리케이션을 설치해본다. 쿠버네티스에서 동작하는 대부분의 애플리케이션은 서비스나 인그레스, 디플로이먼트 같은 쿠버네티스 리소스로 구성된다. 차트는 이 구성을 추상화하고 패키징해 배포하기 위한 것으로, 매니페스트 파일을 복사해 하나 이상의 환경에 배포하는 방식보다 유지 보수성이 좋다.

 

로컬 리포지토리 활성화하기

밑의 명령으로 헬름에서 사용할 수 있는 리포지토리를 확인할 수 있다. 기본 원격 리포지토리와 로컬 리포지토리 정보가 출력될 것이며, 로컬 리포지토리는 헬름이 실행되는 호스트 머신에 위치한다.

 

> helm repo list
NAME  	URL                                             
stable	https://kubernetes-charts.storage.googleapis.com
local 	http://127.0.0.1:8879/charts

 

하지만 이 로컬 리포지토리는 바로 사용할 수 없다. 이 URL에 http 프로토콜로 접근할 수 있어야 우리가 만든 차트를 사용할 수 있으므로 이 웹서버를 실행한다. 로컬 리포지토리에 항상 접근할 수 있도록 서버를 백그라운드로 실행한다.

 

> helm serve &

 

해당 URL을 접근해보면 "Helm Chart Repository"라는 문구가 보일 것이다.

 

차트 템플릿 작성하기

차트를 생성하려면 먼저 차트의 디렉터리 구조를 만들어야 한다. 헬름에 이 템플릿을 만들어주는 기능이 있다.

 

> helm create springboot-web
Creating springboot-web

 

명령 수행후에 명령을 수행한 디렉토리에 밑의 디렉토리 및 파일들이 생성된다.

 

 

posted by 여성게
:
인프라/Docker&Kubernetes 2019. 11. 20. 01:01

 

이전 포스팅에서 쿠버네티스란 무엇이고, 간단하게 팟,레플리카셋,디플로이먼트를 다루어보았다. 이번 시간은 이렇게 띄운 팟을 외부로 서비스할 수 있게 해주는 서비스,인그레스에 대해 다룰 것이다.

 

2019/11/19 - [인프라/Docker for mac] - Kubernetes - Kubernetes란? (클러스터,노드,파드(pod), 리플리카셋, 디플로이먼트)

 

Kubernetes - Kubernetes란? (클러스터,노드,파드(pod), 리플리카셋, 디플로이먼트)

이번 포스팅은 kubernetes에 대해 다루어본다. 사실 쿠버네티스를 다루기 위해서는 docker(도커)에 대한 지식이 필요하지만 여기에서는 다루지 않는다. 그렇다면 쿠버네티스란 무엇인가? 쿠버네티스란? 쿠버네티..

coding-start.tistory.com

 

서비스(Service)

서비스는 쿠버네티스 클러스터 안에서 파드의 집합에 대한 경로나 서비스 디스커버리를 제공하는 리소스다. 서비스의 대상이 되는 파드는 서비스에서 정의하는 레이플 셀렉터로 정해진다.

 

apiVersion: v1
kind: Service
metadata:
  name: sample-service
spec:
  selector:
    app: springboot-web
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8080

 

위는 Service 매니페스트 파일이다. 셀렉터로 우리가 띄운 팟을 참조하고 있다. 그리고 해당 서비스는 80포트로 노출시키고 프로토콜은 TCP이며, 해당 서비스로 들어온 요청을 8080 포트로 포워딩하고 있다.

 

 

하지만 이 서비스는 아직 외부 서비스에 노출되고 있지 않다. External-ip를 보면 아직 할당되지 않았다. 이 말은 클러스터 내부에서만 이 서비스에 접근 가능하다는 것이다. 그렇다면 이 서비스를 어떻게 노출시킬까? 방법은 2가지가 있다. 바로 다음에 다루어보도록 한다.

 

<서비스의 네임 레졸루션>

쿠버네티스 클러스터의 DNS는 서비스를 서비스명.네임스페이스명.svc.local로 연결해준다.
예를 들어 위 서비스는 

http://sample-service.kube-sample.svc.local로 접근가능하며, svc.local이 생략가능하기에
http://sample-service.kube-sample로 접근이 가능하다.

또한 같은 네임스페이스끼리의 접근이라면 네임스페이스 또한 생략가능하다.
http://sample-service

 

ClusterIP 서비스

서비스에도 여러 가지 종류가 있어서 그 종류를 yaml 파일에서 지정할 수 있다. 종류의 기본값은 ClusterIP 서비스다.

 

ClusterIP를 사용하면 쿠버네티스 클러스터의 내부 IP 주소에 서비스를 공개할 수 있다. 이를 이용해 어떤 파드에서 다른 파드 그룹으로 접근할 때 서비스를 거쳐 가도록 할 수 있으며, 서비스명으로 네임 레졸루션이 가능해진다. 다만, 외부로부터는 접근할 수 없다.

 

NodePort 서비스

NodePort 서비스는 클러스터 외부에서 접근할 수 있는 서비스다. NodePort 서비스는 ClusterIP를 만든다는 점은 ClusterIP 서비스와 같다. 각 노드에서 서비스 포트로 접속하기 위한 글로벌 포트를 개방한다는 점이 차이점이다.

 

apiVersion: v1
kind: Service
metadata:
  name: sample-service
spec:
  type: NodePort
  selector:
    app: springboot-web
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8080

 

외부에서 접근해보자. 접근하기전에 해당 서비스와 연결된 외부에서 접근할 포트를 확인하기 위해 아래 명령을 쳐보자.

 

 

외부에서 localhost:30142로 접근해보면, 아래와 같은 결과값이 반환된다. 여기서 중요한 것은 ClusterIP는 외부에서 접근하는 IP가 아니라는 점이다. 클러스터 내부에서 사용되는 IP이기에 외부에서는 접근되지 않는다.

 

 

인그레스(Ingress)

쿠버네티스 클러스터 외부로 서비스를 공개하려면 서비스를 NodePort로 노출시킨다. 그러나 이 방법은 L4 레벨까지만 다룰 수 있기 때문에 HTTP/HTTPS처럼 경로를 기반으로 서비스를 전환하는 L7 레벨의 제어는 불가능하다.

 

이를 해결하기 위한 리소스가 인그레스다. 서비스를 이용한 쿠버네티스 클러스터 외부에 대한 노출과 가상 호스트 및 경로 기반의 정교한 HTTP 라우팅을 할 수 있다.

 

로컬 쿠버네티스 환경에서는 인그레스를 사용해 서비스를 노출하기 위해서는 몇 가지 설정이 더 필요하다. 클러스터 외부에서 온 HTTP 요청을 서비스로 라우팅하기 위한 nginx_ingress_controller를 다음과 같이 배포한다.

 

> kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.16.2/deploy/mandatory.yaml
> kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.16.2/deploy/provider/cloud-generic.yaml

 

이제는 필요한 Ingress Resource를 작성하면 된다. 여기서 작성되는 Ingress는 어떠한 워커에 팟을 띄우는 행위가 아니다. 지금 작성하는 것은 Nginx-ingress에 Rule을 추가하는 행위인 것이다.

 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-sample
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: levi.local.com
    http:
      paths:
        - path: /app
          backend:
            serviceName: sample-service
            servicePort: 80

 

> curl http://localhost/app/api -H "Host:levi.local.com"

 

위의 설정으로 nginx에 룰을 추가하고, 해당 룰로 들어온 요청은 sample-service라는 라우팅 룰을 가지는 팟으로 요청이 전달되는 것이다. 그리고 팟이 여러개라면 로드밸런싱을 nginx가 해준다. 여기까지 간단하게 서비스와 인그레스에 대해 다루어보았다. 사실 간단하게 테스트로 띄우는 정도의 예제였지만 추후에 좀더 실무에 가까운 예제를 다루어볼 것이다.

posted by 여성게
:
인프라/Docker&Kubernetes 2019. 11. 19. 21:55

 

이번 포스팅은 kubernetes에 대해 다루어본다. 사실 쿠버네티스를 다루기 위해서는 docker(도커)에 대한 지식이 필요하지만 여기에서는 다루지 않는다. 그렇다면 쿠버네티스란 무엇인가?

 

쿠버네티스란?
쿠버네티스는 컨테이너 운영을 자동화하기 위한 컨테이너 오케스트레이션 도구이다. 많은 수의 컨테이너를 협조적으로 연동시키기 위한 통합 시스템이며 이 컨테이너를 다루기 위한 API 및 명령행 도구등이 함께 제공된다.
컨테이너를 이용한 애플리케이션 배포 외에도 다양한 운영 관리 업무를 자동화할 수 있다. 도커 호스트 관리, 서버 리소스의 여유를 고려한 컨테이너 배치, 스케일링, 여러 개의 컨테이너 그룹에 대한 로드 밸런싱, 헬스 체크 등의 기능을 갖추고 있다.

 

쿠버네티스 이외에도 도커 컴포즈, 스웜, 스택등을 이용하여 컨테이너 오케스트레이션을 다룰 수 있지만, 쿠버네티스는 더 충실한 기능을 갖춘 컨테이너 오케스트레이션 시스템이자 사실상 가장 표준으로 자리잡은 도구라고 볼 수 있다. 이번 포스팅에서는 완벽한 클러스터 구성을 다루어보지는 못하지만 간단히 로컬에서 예제를 다루어보고 이후에 진짜 여러 머신에서 클러스터 구성하는 방법을 다루어볼 것이다.

 

로컬 PC에서 쿠버네티스 실행

사실 실제 프러덕 환경에서는 사용하기 힘든 방법이지만, 간단히 쿠버네티스가 무엇인지 맛보기 위해 로컬 환경에서 쿠버네티스를 사용해본다. 

 

 

모든 환경은 Mac OS 환경에서 진행한다. 우선 각 PC에 설치된 도커 Preference에 들어가 위와 같이 Enable Kubernetes를 체크해준후 필요한 패키지들을 Install 한다.

 

kubectl 설치

kubectl은 쿠버네티스를 다루기 위한 명령행 도구이다. 로컬 환경이나 매니지드 환경(GKE등) 모두에서 사용할 수 있다.

 

brew install kubernetes-cli

 

kubectl이 잘 설치되었는지 확인해보자.

 

> kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:18:23Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.8", GitCommit:"211047e9a1922595eaa3a1127ed365e9299a6c23", GitTreeState:"clean", BuildDate:"2019-10-15T12:02:12Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}

 

kubernetes dashboard 설치

대시보드는 쿠버네티스에 배포된 컨테이너 등에 대한 정보를 한눈에 보여주는 관리도구이다.

 

 

> kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml
> kubectl proxy

 

여기까지 모두 따라왔다면 아래 url로 접속가능하다.

 

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login

 

접속 후에는 아마 아래와 같은 팝업이 보일 것이다. 2가지 방법의 접속이 있지만 우리는 토큰을 이용한 방법에 대해 다룬다.

 

 

> kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

...
Data
====
ca.crt:     1025 bytes
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi00aDU0eiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjczYWNkOGEzLTBhYjctMTFlYS1hMjRkLTAyNTAwMDAwMDAwMSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.JtykwdSsrqSPb45KieBxoLTgZ-EK2PPTsdsDHr-xJFmFqbMwduui9uQIJH0gFW53iLw_ySb6FpSKRoDNuKbNO-gs89DnGStfogu1ldOS4X4xxZAPIq3za-83OpBRNLGqG8nvPsHSYHPWhJ-vIHxImchlFv0xZDAQJklpIMWX2oQJMsBOkp688RnZ5xCm16YgqIFPCd712hfMufmHFzcdtd7U-Ma3fK6Jkl_FG7E_ee3o3E8kp3_HPdCcQkfMQwPtnvIGf21gmXLisGUsI12J-xdYt8ElmlU7wav0BjB7T-PK4LMUP_KmYytWTnpJL-okrU83wbOoblOyZitpNNHijQ

 

위와 같은 명령을 통해 쿠버네티스 대시보드 접속을 위한 토큰 값을 얻을 수 있다. 토큰 값을 복사해 접속해보자 .

 

 

쿠버네티스의 주요 개념

쿠버네티스로 실행하는 애플리케이션은 애플리케이션을 구성하는 다양한 리소스가 함께 연동해 동작한다. 여기서 말하는 쿠버네티스의 리소스란 애플리케이션을 구성하는 부품과 같은 것으로 앞으로 설명할 노드, 네임스페이스, 파드 등을 가리킨다.

 

쿠버네티스 클러스터와 노드

쿠버네티스 클러스터는 쿠버네티스의 여러 리소스를 관리하기 위한 집합체를 말한다. 여타 엘라스틱서치, 레디스 등 많은 미들웨어에서 사용하는 클러스터라는 용어와 크게 다르지 않다. 

 

쿠버네티스 리소스 중에서 가장 큰 개념은 노드(node)이다. 노드는 클러스터의 관리 대상으로 등록된 도커 호스트로, 도커 컨테이너가 배치되는 대상이다. 그리고 쿠버네티스 클러스터 전체를 관리하는 서버인 마스터가 적어도 하나 이상 있어야한다. 여기서 하나 이상이라는 말은 클러스터가 작동하기 위한 최소 조건이지만 실제 프러덕 환경에서는 절대 하나로 클러스터를 구성하지 않는다. 최소 3개 이상의 마스터 노드를 갖는 것이 좋다.

 

 

쿠버네티스는 노드의 리소스 사용 현황 및 배치 전략을 근거로 컨테이너를 적절히 배치한다. 다시 말해 클러스터에 배치된 노드의 수, 노드의 사양 등에 따라 배치할 수 있는 컨테이너 수가 결정된다는 뜻이다.

 

마스터를 구성하는 관리 컴포넌트

쿠버네티스의 마스터 노드에 배포되는 관리 컴포넌트에는 다음과 같은 것이 있다.

 

컴포넌트 역할
kube-apiserver 쿠버네티스 API를 노출하는 컴포넌트이다. kubectl로부터 리소스를 조작하라는 지시를 받는다.
etcd 고가용성을 갖춘 분산 키-값 스토어이다. 쿠버네티스 클러스터의 백킹 스토어로 사용된다.
kube-scheduler 노드를 모니터링하고 컨테이너를 배치할 적절한 노드를 선택한다.
kube-controller-manager 리소스를 제어하는 컨트롤러를 실행한다.

 

 

네임스페이스

쿠버네티스는 클러스터 안에 가상 클러스터를 또 다시 만들 수 있다. 이 클러스터 안의 가상 클러스터를 네임스페이스라고 한다. 클러스터를 처음 구축하면 default, docker, kube-public, kube-system의 네임스페이스 4개가 이미 만들어져 있다. kubectl get namespace 명령으로 현재 클러스터 안에 존재하는 네임스페이스의 목록을 확인할 수 있다.

 

> kubectl get namespace
NAME                   STATUS   AGE
default                Active   42m
docker                 Active   41m
kube-node-lease        Active   42m
kube-public            Active   42m
kube-system            Active   42m
kubernetes-dashboard   Active   25m

 

네임스페이스가 위에 설명에서는 클러스터 안의 가상 클러스터라고 설명했다. 사실 이해가 힘들수 있다. 쉽게 전체 클러스터에서 리소스의 구분 용도라고 생각해도 좋을 듯하다. 즉, 전체 클러스터에서 특정 이름으로 클러스터의 영역을 구분하는 것이다.

 

파드(pod)

파드는 컨테이너가 모인 집합체의 단위로, 적어도 하나 이상의 컨테이너로 이루어진다. 여기서 말하는 컨테이너는 도커 컨테이너를 이야기한다. 쿠버네티스를 도커와 함께 사용한다면 파드는 컨테이너 하나 혹은 컨테이너의 집합체가 된다.

 

쿠버네티스에서는 결합이 강한 컨테이너를 파드로 묶어 일괄 배포한다.(ex spring web app + nginx) 

 

 

또한 이러한 팟은 노드에 배치된다.

 

 

한 팟 안의 컨테이너는 모두 같은 노드에 배치된다. 다시 말해, 팟 하나가 여러 노드에 걸쳐 배치될 수는 없다.

 

그렇다면 가장 먼저 고민되는 부분은 '팟의 적절한 크기는 어느 정도인가'가 될 것이다. 보통 리버스 프록시 역할을 할 Nginx와 그 뒤에 위치할 애플리케이션 컨테이너를 함께 팟으로 묶는 구성이 일반적이다. 또한 예거와 같은 로그와 관련된 서버는 애플리케이션 컨테이너의 사이드카로 많이 팟을 구성한다.

 

또 함께 배포해야 정합성을 유지할 수 있는 컨테이너 등에도 해당 컨테이너를 같은 팟으로 묶어두는 전략이 유용하다. 

 

파드(pod) 생성 및 배포하기

파드 생성은 kubectl만 사용해도 가능하지만, 버전 관리 관점에서도 yaml 파일로 정의하는 것이 좋다. 쿠버네티스의 여러 가지 리소스를 정의하는 파일을 매니페스트 파일이라고 한다.

 

우선 매니페스트 파일을 이용하여 컨테이너 설정을 하기 이전에 간단히 도커 이미지와 컨테이너에 대해 다루어보자.

 

개념 역할
도커 이미지 도커 컨테이너를 구성하는 파일 시스템과 실행할 애플리케이션 설정을 하나로 합친 것으로 컨테이너를 생성하는 템플릿 역할을 한다.
도커 컨테이너 도커 이미지를 기반으로 생성되며, 파일 시스템과 애플리케이션이 구체화돼 실행되는 상태.

 

모든 소스 및 Dockerfile은 깃헙에 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@SpringBootApplication
public class SampleApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
 
    @RequestMapping("/")
    public String index(){
        return "Hello Kubernetes!";
    }
 
}
cs

 

간단히 "localhost:8080/"을 호출하였을 때 "Hello Kubernetes!"를 출력하는 예제이다. 해당 애플리케이션을 도커이미지로 만들기 위한 Dockerfile이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM openjdk:8-jdk
# 어떤 이미지로부터 새로운 이미지를 생성할 지 지정. 플랫폼 : 버전 형태로 작성
MAINTAINER levi <1223yys@naver.com>
# Dockerfile을 생성-관리하는 사람
VOLUME /tmp
# 호스트의 directory를 docker 컨테이너에 연결. 즉 소스코드나 외부 설정파일을 커밋하지 않고 docker container에서 사용가능하도록 함
RUN mkdir -/app/
# 도커 이미지 생성시 실행
ADD ./build/libs/sample-0.0.1-SNAPSHOT.jar /app/app.jar
# 파일이나 디렉토리를 docker image로 복사
EXPOSE 8080
# 외부에 노출할 포트 지정
CMD ["java""-jar""/app/app.jar"]
# docker image가 실행될 때 기본으로 실행될 command
cs

 

해당 파일을 프로젝트 root에 위치시켜준다.(Dockerfile) 이후 해당 도커파일을 기반으로 이미지를 빌드해준다.

 

> docker build -t 1223yys/springboot-web:0.1.6 . #도커이미지 빌드
> docker image ls #이미지가 잘 생성되었는지 확인
> docker run -d -p 8080:8080 1223yys/springboot-web:0.1.6 #도커 컨테이너 실행
> docker ps #컨테이너가 잘 실행되고 있는지 확인

 

빌드 완료후 간단히 테스트를 위하여 로컬 도커에서 컨테이너를 실행해보자. 해당 이미지는 Docker Hub에 배포한 상태이다. 추후에 Kubernetes 리소스 파일 작성시 사용하기 위한 배포인 것이다.

 

> docker push 1223yys/springboot-web:0.1.6

 

파드(pod) 매니페스트 작성

 

apiVersion: v1
kind: Pod
metadata:
  name: springboot-web
spec:
  containers:
  - name: springboot-web
    image: 1223yys/springboot-web:0.1.6
    ports:
    - containerPort: 8080
    

 

kind는 이 파일에서 정의하는 쿠버네티스 리소스의 유형을 지정하는 속성이다. 이 파일은 파드를 정의하는 파일이므로 속성값이 Pod이다. kind 속성에 따라 spec 아래의 스키마가 변화한다. metadata는 이름 그대로 리소스에 부여되는 메타 데이터이다. spec은 리소스를 정의하기 위한 속성으로, 파드의 경우 파드를 구성하는 컨테이너를 containers 아래에 정의한다.

 

containers 속성 아래의 값들을 보자. name은 컨테이너 이름, image는 도커 허브에 저장된 이미지 태그값을 지정한다. 포트는 외부에 노출시킬 포트번호이다. 

 

이제 위의 설정을 바탕으로 팟을 띄워보자. 팟을 띄우기 전에 샘플용 네임스페이스 하나를 생성한다. 그리고 팟을 띄워보도록 한다.

 

> kubectl create namespace kube-sample
> kubectl apply -f pod-sample.yaml -n kube-sample
> kubectl get pod -n kube-sample

 

아래 이미지와 같이 나왔다면 팟이 정상적으로 뜬 것이다.

 

 

팟을 다루는 기타 명령이다.

 

pod-sample -> yaml 파일명
springboot-web -> pod 이름
kube-sample -> 네임스페이스 이름

> kubectl get pod #떠있는 팟 목록을 가져온다
> kubectl logs -f springboot-web -c springboot-web -n kube-sample #표준 출력 로그를 본다.
> kubectl delete pod springboot-web #pod 삭제
> kubectl delete -f pod-sample.yaml

 

여기서 파드에 대한 설명을 보충하자면, 파드에는 각각 고유의 가상 IP주소가 할당된다. 파드에 할당된 가상 IP 주소는 해당 파드에 속하는 모든 컨테이너가 공유한다. 즉, 같은 파드 안의 모든 컨테이너의 가상 IP 주소가 같기 때문에 컨테이너간의 localhost 통신이 가능해진다. 하지만 다른 팟 간에는 localhost 통신이 당연히 불가능하다.(할당된 가상 IP 주소가 다르기 때문)

 

레플리카세트(ReplicaSet)

파드를 정의한 매니페스트 파일로는 파드를 하나밖에 생성할 수 없다. 그러나 어느 정도 규모가 되는 애플리케이션을 구축하려면 같은 파드를 여러 개 실행해 가용성을 확보해야 하는 경우가 생긴다. 이런 경우 사용하는 것이 레플리카세트이다. 레플리카세트는 똑같은 정의를 갖는 파드 여러개를 생성하고 관리하기 위한 리소스이다.

 

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: sample-replicaset
  labels:
    app: springboot-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: springboot-web
  template:
    metadata:
      labels:
        app: springboot-web
    spec:
      containers:
      - name: web-app
        image: 1223yys/springboot-web:0.1.6
        ports:
        - containerPort: 8080

 

간단하게 매니페스트 파일을 설명하자면, apiVersion은 리소스 유형마다 조금씩 다르다. 왜냐 각 리소스마다 호출하는 api path가 다르기 대문에 잘 확인하자. 그리고 kind는 ReplicaSet이고, metadata에는 이름등을 정의한다. 두번째는 ReplicaSet의 spec 부분이다. 이전 Pod의 매니페스트와는 조금 다르게 replicas와 selector가 생겼다. 우선 replicas는 몇개의 복제본을 만들것인가를 정의하고, selector는 어떠한 Pod을 대상으로 ReplicaSet을 만들것인가를 지정한다. matchLabels의 값으로 template 밑의 라벨 값이 선택되었다. template 밑의 설정들은 Pod의 설정과 동일하다. 이 말은 즉, selector 속성으로 복제할 Pod의 설정을 참조하는 것이다. 이제 정말 레플리카셋이 잘 떴는지 확인하자.

 

> kubectl describe replicasets -n kube-sample

 

해당 명령은 레플리카셋의 리소스에 대한 자세한 설명이 담겨있다. 

 

> kubectl get replicasets,pod -n kube-sample

 

 

해당 명령으로 하나의 레플리카셋이 떠있으며 이 레플리카셋에 설정된 리소스로 Pod이 총 3개 떠있는 것을 확인할 수 있다.

 

디플로이먼트(deployment)

레플리카셋보다 상위에 해당하는 리소스로 디플로이먼트가 있다. 보통 디플로이먼트가 애플리케이션 배포의 기본 단위가 되는 리소스이다. 레플리카셋은 똑같은 팟의 레플리카를 관리 및 제어하는 리소스인데 반해, 디플로이먼트는 레플리카셋을 관리하고 다루기 위한 리소스이다.

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
  labels:
    app: springboot-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: springboot-web
  template:
    metadata:
      labels:
        app: springboot-web
    spec:
      containers:
      - name: web-app
        image: 1223yys/springboot-web:0.1.6
        ports:
        - containerPort: 8080

 

사실 디플로이먼트의 설정은 레플리카셋과 크게 다르지 않다. 차이가 있다면 디플로이먼트가 레플리카셋의 리비전 관리를 할 수 있다는 정도이다.

 

 

총 리소스 타입이 3개가 뜬 것을 볼 수 있다.

 

 

디플로이먼트는 위와 같이 리비전이 관리된다. 하지만 change-cause가 보이지 않는다. 이것을 apply할때 옵션을 하나 빠트려서 그런다.

 

 

이렇게 디플로이먼트는 리비전관리가 되기 때문에 레플리카셋 대신 배포의 기본단위가 된다.

 

레플리카세트의 생애주기

 

쿠버네티스는 디플로이먼트를 단위로 애플리케이션을 배포한다. 실제 운영에서는 레플리카세트를 직접 다루기 보단 디플로이먼트 매니페스트 파일을 통해 다루는 경우가 대부분이다.

 

디플로이먼트가 관리하는 레플리카세트는 지정된 개수만큼 파드를 화곱하거나 파드를 새로운 버전으로 교체하거나 이전 버전으로 롤백하는 등 중요한 역할을 한다.

 

애플리케이션 배포를 바르게 운영하려면 이러한 레플리카세트가 어떻게 동작하는지 파악할 수 있어야 한다. 디플로이먼트를 수정하면 레플리카세트가 새로 생성되고 기존 레플리카세트와 교체된다.

 

파드 개수만 수정하면 레플리카세트가 새로 생성되지 않음

매니페스트 파일에서 replicas 값을 3->4로 수정해 반영하자. 그리고 팟의 정보를 보면(kubectl get pod -n kube-sample) 기존 팟을 그대로 있고, 새로운 컨테이너가 새로 생성되는 것을 알 수 있다.

 

레플리카세트가 새로 생성됬다면 리비전 번호가 2일 텐데, 그 내용은 출력되지 않는다. replicas 값만 변경해서는 레플리카세트의 교체가 일어나지 않는다.

 

 

컨테이너 정의 수정

만약 새로운 API가 추가되어 컨테이너의 수정이 있다고 해보자. 그렇다면 레플리카셋은 어떻게 될까? 새로운 엔드포인트를 추가하여 도커이미지를 새로운 태그로 빌드하고 디플로이먼트의 Pod의 이미지 태그를 변경해보자.

 

 

기존 팟들이 내려가고 새로운 팟들이 생성되고 있으며, 새로운 리비전이 하나 생겨났다.

 

롤백 실행하기

디플로이먼트는 리비전 번호가 기록되므로 특정 리비전의 내용을 확인할 수 있다.

 

> kubectl rollout history deployment sample-deployment --revision=1

 

 

> kubectl rollout undo deployment sample-deployment -n kube-sample

 

위 undo 명령을 실행하면 바로 이전의 리비전 상태의 디플로이먼트로 되돌아 갈 수 있다. 만약 애플리케이션 배포후 문제가 있다면 바로 롤백할 수 있기때문에 좋은 기능이 될 것이다.

 

여기까지 쿠버네티스가 무엇인지 Pod,RepliaSets,Deployment에 대해 간단히 다루어보았다. 하지만 여기까지 진행해서는 실제 애플리케이션을 사용해 볼수 없다. 우리가 띄운 Pod을 외부에 노출시키기 위해서는 서비스, 인그레스라는 애들이 필요하다. 서비스 및 인그레스 리소스는 다음 포스팅에서 다루어볼 것이다.

posted by 여성게
:
인프라/Docker&Kubernetes 2019. 9. 13. 17:33

 

이번 포스팅은 Docker를 이용하여 MongoDB를 설치하는 방법이다.

 

 

도커 실행 후 MongoDB 이미지를 받아준다.

 

 

이미지가 잘 받아진 것을 확인한다.

 

 

이제 내려받은 이미지를 실행시키자. 

 

각 옵션은 이전 도커를 이용하여 오라클을 받는 옵션과 크게 다르지 않으므로 이전 포스팅을 참고하자. 위에서는 아니지만 만약 위에 실행한 명령에 마지막에 "--auth"를 붙인다면, 몽고디비 서버에 접속할때 인증이 필요하게 된다. 

 

> docker run --name mongodb -v localpath:containerpath -d -p 27017:27017 mongo --auth

 

유저를 만들기 위한 설명은 아래 링크참조를 참조하면 될듯하다.

 

 

DB - MongoDB CRUD 사용방법 및 기타 사용방법 - 1

이번 포스팅은 간단하게 MongoDB 사용법에 대해 다루어봅니다. 모든 쿼리는 특정 클라이언트 드라이버를 이용하는 것이 아니라, Shell을 이용하여 직접 쿼리를 작성해보는 내용입니다. 실습 이전에 혹시나 몽고디..

coding-start.tistory.com

 

Mac OS - docker oracle11g 설치

mac os 환경에서 docker를 이용한 oracle 11g 설치 우선 진행하기 전에 자신의 os에 맞는 docker를 다운로드 해줍니다. 1)docker pull wnameless/oracle-xe-11g =>oracle 11g 도커이미지 다운로드, 여기서 이미지..

coding-start.tistory.com

 

 

잘 실행되고 있다 ! 역시 도커란 녀석은 아주 편하다.

 

이후 아래 명령어를 통해 컨테이너에 접속해 조작가능하다.

 

> docker exec -it mongodb bash

 

 

> mongo

 

mongo 명령으로 몽고디비서버를 실행시켜서 shell 환경에서 조작할 수 있다.

 

 

그리고 마운트한 디렉토리를 들어가보니 아래와 같은 파일들이 생겨있다.

 

 

요즘 막 몽고디비를 공부하고 있는데, 기본으로 WiredTiger를 스토리지 엔진으로 사용하고 있는 것 같다. 몽고디비가 플러그인해서 쓸 수있는 스토리지 엔진이 WiredTiger 말고도 더 있는데, 각각 구현되고 있는 방식이 달라 트랜잭션 등의 기능이 조금씩 다르게 제공된다는 데, 이런 것들은 추후에 다루어 봐야겠다.

posted by 여성게
:
인프라/네트워크(기초) 2019. 8. 4. 20:11

실습은 Mac OS 환경에서 진행하였습니다.

 

ssh로 원격서버에 접속할 때 매번 비밀번호 치는 것은 귀찮은 작업입니다. 그리고 Git과 같이 버전관리 시스템도 ssh로 원격접속하는 경우가 많은데 이때도 매번 비밀번호를 쳐줘야하는 귀찮은 작업이 있기에 이번에 알아볼 내용은 비밀번호없이 ssh 접속하는 방법입니다.

 

 

모두 3번의 엔터를 치고 키를 생성하였습니다. 첫번째 엔터는 키 파일을 만들겠냐, 두번째,세번째는 키파일의 암호를 만들어주는 것인데 필자는 따로 암호를 만들지 않을 것임으로 모두 엔터를 쳐 넘어갔습니다.

 

 

이제 /home/.ssh에 두개의 파일이 생성되었을 텐데, id_rsa는 우리가 사용할 비밀키입니다. 절대로 유출되어서는 안되는 파일입니다. 그리고 id_rsa.pub은 원격 접속할 서버에서 사용할 우리의 공개키입니다. 권한은 절대 변경하시지 말고 사용하시길 바랍니다. 이 파일들을 어떻게 사용하냐면 우리가 생성한 공개키를 원격서버에 저장합니다. 그리고 우리는 원격서버에 접속할때 비밀번호를 치지않고 우리의 비밀키를 이용하여 원격서버에 접속을 하게 됩니다. 즉, 사용자가 직접 비밀번호를 치는 것이 아니라 OS가 내부적으로 원격서버의 공개키, 그리고 우리의 비밀키와 대조하여 인증을 대신하게 됩니다. 

 

id_rsa.pub 안에 있는 공개키 내용을 원격 서버의 /home/.ssh/authorized_keys 라는 파일에 저장할 것입니다. 만약 원격 서버에 authorized_keys라는 파일이 없으면 생성해주시면 되는데, 중요한 것은 파일의 내용을 임의로 바꾸시지 마시고 위의 파일명과 동일하게 만들어주셔야 합니다. 그리고 id_rsa.pub안에 있는 내용을 빠짐없이 전부 authorized_keys에 저장하여야합니다.

 

그런데 매번 id_rsa.pub에 있는 내용을 복사해서 원격서버에 들어가 authorized_keys에 공개키를 저장하는 것은 귀찮은 작업입니다. 이럴때 사용할 수 있는 명령어를 소개하겠습니다.

 

>ssh-copy-id id@ip

 

위에 보시는 것처럼 ssh-copy-id라는 명령어의 인자로 접속할 원격 서버의 계정명@원격서버ip를 입력해주시면 우리의 공개키를 원격서버의 /home/.ssh/authorized_keys에 추가해줍니다.

 

이제 모든 작업이 완료되었습니다.

 

>ssh id@ip

 

위의 명령어로 원격서버에 접속하면 첫번째 접속만 빼고는 이제 비밀번호 없이 접속이 가능해집니다!

 

posted by 여성게
:
인프라/네트워크(기초) 2019. 8. 1. 22:21

 

오늘 포스팅할 내용은 간단하게 HTTP와 HTTPS와의 차이점을 보고 더 나아가 HTTPS에 대해 다루어보려 한다. 

 

HTTP VS HTTPS

웹 개발을 하는 개발자라면 HTTP 프로토콜이라는 것을 모르지 않을 것이다. HTTP란 Hypertext Transfer Protocol의 약자이다. OSI 7계층 중 응용계층에 위치하고 있는 프로토콜이다. 이 프로토콜은 간단히 네트워크 구간에서 HTML문서를 전송하기 위한 통신규약이다. 물론 HTML 문서만을 주고 받는 것은 아니지만 간단히 쉽게 HTML을 주고 받기 위한 프로토콜이라고 생각하자. 그렇다면 HTTPS란 무엇일까? HTTPS는 Hypertext Transfer Protocol Over Secure Socket Layer의 약자로 Secure라는 단어가 포함되어 있는 것을 보면 알 수 있듯이 보안이 강화되면 HTTP 프로토콜이다. 지난 포스팅 중에 Wireshark를 이용해 간단히 HTTP의 패킷을 분석해보았을 때, POST로 보낸 데이터가 평문 텍스트로 그대로 노출되어 있는 것을 볼 수 있었다. 즉, 암호화되지 않은 데이터를 전송하기 때문에 서버와 클라이언트가 주고 받는 메시지를 그대로 노출하기 때문에 보안에 아주 취약하다. 이러한 점을 보완하여 보안을 더욱 강화한 프로토콜이 HTTPS인 것이다. 

 

2019/08/01 - [네트워크(기초)] - 네트워크 - Wireshark(와이어샤크) 설치 및 패킷 분석 예제

 

네트워크 - Wireshark(와이어샤크) 설치 및 패킷 분석 예제

오늘 다루어볼 포스팅 내용은 Wireshark를 이용한 네트워크 패킷 분석 예제입니다. HTTP/HTTPS 포스팅을 위한 선행 작업이라고 볼 수 있을 것 같습니다. 모든 환경은 Mac OS 환경에서 진행되었음을 알려드립니다...

coding-start.tistory.com

 

그렇다면 HTTPS는 어떻게 동작할까? 간단히 HTTPS는 SSL이라는 보안 프로토콜 위에서 동작하는 HTTP라고 생각 할 수 있다.

 

그렇다면 SSL,TLS란 무엇일까? 아래 그림과 같이 살펴보자.

 

SSL(Secure Sockey Layer)란 보안 소켓 계층을 이르는 것으로, 인터넷 상에서 데이터를 안전하게 전송하기 위한 인터넷 암호화 통신 프로토콜을 말한다. SSL은 전자상거래 등의 보안을 위해 넷스케이프에서 처음 개발되었고, 시간이 지나 IETF에 의해 SSL3.0을 이용해TLS(Transport Layer Security)로 표준화 하였다. 즉, 간단히 이야기하면 SSL == TLS이다.(물론 표준화되면서 기능상 차이가 있을 지는 모르지만 결국 SSL를 표준화한 것이 TLS이다.)

 

위의 그림을 보자. SSL/TLS는 어떠한 계층에 올라가있을까? 사실 어느 계층에 속해있다고 이야기하기는 힘들다. SSL/TLS는 응용계층과 전송계층 사이에서 동작하는 독립적인 프로토콜이라고 생각하면 좋다. 자세한 동작 방식을 설명하기 전에 간단한 SSL 플로우를 이야기하자면 응용계층의 HTTP 프로토콜에서 사용자의 데이터를 받고 전송계층으로 캡슐화되기 이전에 SSL 프로토콜에 의해서 사용자의 데이터가 암호화된다. 그리고 서버는 전송계층에서 세그먼트를 받아 SSL 계층에서 데이터를 복호화하여 응용계층까지 보낸다. 즉, 우리는 SSL 프로토콜만 적용하면 마치 애플리케이션은 SSL을 TCP로 인식하고 TCP는 SSL을 애플리케이션으로 인식하는 것처럼 통신하기 때문에 우리가 별도로 통신에 대해 손댈것은 없다.

 

SSL은 TCP 위에서 Record Protocol을 통해 실질적인 보안서비스를 제공하고 Handshake Procotol, Change Cipher Spec Protocol, Alert Protocol을 통해 SSL 동작에 관한 관리를 하게 된다. 

 

1.Record Protocol

Record protocol은 데이터의 압축을 수행하여 안전한 TCP패킷으로 변환하고, 데이터 암호화 및 무결성을 위한 메시지 인증을 수행하는 프로토콜로 Handshake Protocol, Change Cipher Spec Protocol, Alert Protocol 그리고 Application Protocol을 감싸는 역할을 한다.

 

-Protocol 필드에는 Change Cipher Spec을 나타내는 20이 들어간다.

-data를 보내기 좋게 자르거나 붙이고 선택적으로 압축하여 MAC(Message Authentication Code)을 적용하고 암호화하여 이를 TCP로 전달

 

2.Change Cipher Spec Protocol

암호화 알고리즘과 보안 정책을 송수신 측간에 조율하기 위해 사용하는 프로토콜로 프로토콜의 내용에는 단 하나의 바이트, 언제나 1이라는 값이 들어간다.

 

3.Alert Protocol

2바이트로 구성되며, 첫번째 바이트에는 warning 또는 fatal이 들어가고 두번째 바이트에는 handshake, change cipher spec, record protocol 수행 중 발생하는 오류메시지가 들어가게 된다.

 

-Warning : 주의해야 하는 문제, 연결 미종료

-Fatal : 매우 중요한 문제, 연결 종료

 

4.Handshake Protocol

암호 알고리즘 결정, 키 분배, 서버 및 클라이언트 인증을 수행하기 위해 사용되는 프로토콜이다. 아래 그림은 간단한 해당 프로토콜의 동작방식이다.

 

 

SSL 전체 통신 과정

자 지금까지 이론을 다루어 보았는데, 실제 동작에 대해서 알아보자. 우선 SSL 설명 전에 암호화 방식에 대해 간단히 다루어보자.

 

암호를 만드는 행위인 암호화를 할 때 사용하는 일종의 비밀번호를 키(key)라고 한다. 이 키에 따라서 암호화된 결과가 달라지기 때문에 키를 모르면 암호를 푸는 행위인 복호화를 할 수 없다.

 

-대칭키 : 하나의 키로 데이터를 암호화하고 복호화한다. 하나의 키로 암복호화를 하기 때문에 해당 키가 노출된다면 보안상 아주 치명적인 문제가 발생한다. 장점이라고 하면 암복호화에 드는 비용이 적다.

 

대칭키 방식은 단점이 있다. 암호를 주고 받는 사람들 사이에 대칭키를 전달하는 것이 어렵다는 점이다. 대칭키가 유출되면 키를 획득한 공격자는 암호의 내용을 복호화 할 수 있기 때문에 암호가 무용지물이 되기 때문이다. 이런 배경에서 나온 암호화 방식이 비대칭키(공개키)방식이다.

 

-비대칭키 : 2개의 키(공개키,비공개키)로 암호화&복호화한다. 즉, 공개키로 데이터를 암호화하면 반드시 비밀키로만 복호화 가능하고 비밀키로 데이터를 암호화하면 공개키로만 복호화할 수 있다.  이 방식에 착안해서 두개의 키 중 하나를 비공개키(private key, 개인키, 비밀키라고도 부른다)로하고, 나머지를 공개키(public key)로 지정한다. 비공개키는 자신만이 가지고 있고, 공개키를 타인에게 제공한다. 그렇다면 암호화,복호화의 주체가 되는 키에 따른 특징을 무엇일까?

1)암호화-공개키,복호화-비공개키 : 진짜 데이터를 암호화하여 보호하기 위한 목적이다.

2)암호화-비공개키,복호화-공개키 : 인증을 위한 목적이다. 즉, 서버에서 비공개키로 데이터를 암호화해서 보냈고 클라이언트에서 공개키로 복호화가 된다면 최소한 해당 서버는 클라이언트 입장에서 신뢰할 수 있다는 인증과정을 거치게 된것이다.

 

위의 두개의 개념들은 SSL에서 사용되는 개념이다. 꼭 알아두어야 한다. SSL에서는 두가지 방식을 혼합하여 사용한다.

 

 

위의 그림을 살펴보자. 우리가 평소에 아는 것은 Client&Server이다. 하지만 위에 Host responps with valid SSL certificate 라는 생소한 것이 있다. 이것은 무엇일까?

 

CA

인증서의 역할은 클라이언트가 접속한 서버가 클라이언트가 의도한 서버가 맞는지를 보장하는 역할을 한다. 이 역할을 하는 민간기업들이 있는데 이런 기업들을 CA(Certificate authority) 혹은 Root Certificate 라고 부른다. CA는 아무 기업이나 할 수 있는 것이 아니고 신뢰성이 엄격하게 공인된 기업들만이 참여할 수 있다. 그 중에 대표적인 기업들은 아래와 같다. 수치는 현시점의 시장점유율이다. (위키피디아 참조)

  • Symantec (VeriSign, Thawte, Geotrust) with 42.9% market share
  • Comodo with 26%
  • GoDaddy with 14%
  • GlobalSign with 7.7%

SSL을 통해서 암호화된 통신을 제공하려는 서비스는 CA를 통해서 인증서를 구입해야 한다. CA는 서비스의 신뢰성을 다양한 방법으로 평가하게 된다.

 

즉, 개발자 입장에서 우리가 서버를 개발하는 개발자이다. 모든 개발이 끝나고 오픈을 하기위해 HTTPS를 적용하려고 한다. 그렇다면 우리는 신뢰할 수 있는 CA 기업에 인증서를 구입하여야 한다.(물론 무료인 인증서도 있지만 브라우저가 신뢰할 수 있는 CA이며 무료인 것은 많지 않다. 1년간 무료 인증서를 제공하는 starcom이라는 기업뿐이다.) 인증서를 구입하면 CA는 우리에게 무엇을 줄까? 바로 인증서를 준다. 정확히 말하면 CA기업의 비밀키를 이용하여 암호화한 인증서를 주는 것이다. 그렇다면 인증서에는 어떠한 정보가 들어가 있을까?

 

SSL 인증서에 들어가 있는 정보

  • 서비스의 정보(인증서를 발급한 CA, 서비스의 도메인 등)
  • 서버 측 공개키(공개키의 내용, 공개키의 암호화 방법)

위에서는 이야기 하지 않았지만 CA기업은 우리에게 암호화된 인증서 + 서버에서 사용할 비밀키까지 쥐어준다. 그렇기 때문에 해당 비밀키와 함께 사용될 공개키를 SSL 인증서 안에 담아주는 것이다. 집중한 사람은 여기서 의문이 생길 것이다. 그러면 서버에서 사용할 비밀키를 받았고 클라이언트가 사용할 공개키는 인증서 안에 담겨 있는데, 그렇다면 CA의 비밀키로 암호화된 인증서를 복호화할 공개키는 어디있지? 답은 브라우저에 있다. 우리가 사용하는 크롬,IE,사파리,파이어폭스 등에는 이미 신뢰할 수 있는 CA 기관의 리스트와 해당 기관의 공개키를 이미 가지고 있다. 나머지 내용은 밑에서 설명한다.

 

SSL의 인증서의 역할

그렇다면 SSL 인증서가 우리에게 해주는 역할은 무엇일까?

  1. 클라이언트가 접속한 서버가 신뢰 할 수 있는 서버임을 보장한다.
  2. SSL 통신에 사용할 공개키를 클라이언트에게 제공한다.

 

위의 그림을 보면서 자세한 동작을 확인하자.

 

1)클라이언트는 브라우저에 들어가 접속한 URL을 치고 엔터를 친다.

-HTTP 통신을 위해서는 3-way-handshake(TCP연결수립)라는 동작을 한다.  하지만 HTTPS는 HTTP와는 조금 다른 3-way-handshake 작업을 한다. 위 4번의 handshake protocol글을 참조하자.

즉, HTTPS의 3-way-handshake 과정에서 클라이언트는 서버에게 SSL 인증서를 전달받는다. 그리고 전달받은 SSL인증서를 브라우저가 내부적으로 가지고 있는 CA리스트와 CA공개키를 이용해 신뢰할 수 있는 기관의 인증서인지를 검사한다. 그리고 데이터 암호화를 위한 대칭키를 생성한다.

 

 

다음은 Wireshark를 이용하여 HTTPS 통신의 패킷을 분석한 결과이다.

 

 

다수의 과정을 통해 클라이언트가 서버에 접속한다. 다시 뒤로 돌아가서 HTTPS로 통신을 하면 네트워크 통신과정에서 주고 받는 데이터가 암호화 된다. 그렇다면 클라이언트의 데이터는 어떻게 암호화할까? SSL은 대칭키와 비대칭키를 혼합해서 사용한다고 했다. 즉, 클라이언트의 데이터는 대칭키로 암호화한다! 그렇다면 이 대칭키는 어떻게 만들까? 인증서에는 클라이언트가 사용할 공개키 밖에 없다고 했는데? 이것은 위의 그림의 과정 중에 만들어진다. Client Hello,Server Hello 등의 과정에서 클라이언트와 서버는 각각 생성한 랜덤 데이터를 주고 받는다. 또한 사용 가능한 암호화 방식들을 주고 받는다. 대칭키는 바로 서로 주고 받는 랜덤 데이터를 이용하여 만들게 되는 것이다. 그리고 매번 통신을 할때 3-way-handshake 과정을 거치는데 이때 매번 새로운 대칭키가 만들어진다.

어? 대칭키는 키 유출시에 보안에 굉장히 취약하다고 했는데.. 여기서 바로 인증서에 있는 클라이언트 공개키를 이용하는 것이다. 인증서에 있는 공개키를 이용하여 랜덤데이터(클,서)로 만든 대칭키를 암호화하는 것이다. 그리고 서버에서는 자신의 비공개키로 암호화된 대칭키를 복호화하고 복호화된 대칭키로 클라이언트 데이터를 다시 복호화한다. 복잡하다.. 다시 정리해보자

 

1.클라이언트가 접속한 서버가 신뢰 할 수 있는 서버임을 보장한다.

1)클라이언트는 서버로 접속하여 CA의 SSL 인증서를 응답으로 받는다.

2)브라우저는 SSL인증서가 신뢰할 수 있는 CA기관의 인증서인지 확인한다.(여기서 브라우저가 내부적으로 가지고 있는 CA리스트와 각 CA의 공개키를 이용해 SSL인증서를 복호화한다.)

 

처음에 비밀키로 암호화하고 공개키로 복호화하면 인증과 같은 용도로 사용된다고 이야기했다.

 

2.SSL 통신에 사용할 공개키를 클라이언트에게 제공한다.

1)클라이언트와 서버의 3-way-handshake 과정에서 클라이언트와 서버가 생성한 랜덤데이터를 이용해 대칭키를 만든다.

2)클라이언트는 해당 대칭키로 서버에 보낼 데이터를 암호화한 후에 SSL인증서에 담겨있는 공개키를 이용하여 대칭키를 암호화한다.

3)암호화한 데이터와 암호화한 대칭키를 서버로 전송한다.

4)서버는 자신의 비밀키로 암호화된 대칭키를 복호화하고 해당 대칭키로 클라이언트가 보낸 암호화된 데이터를 복호화한다.

 

공개키로 암호화하고 비밀키로 복호화하는 것은 진짜 보낼 데이터를 암호화하여 노출되지 않게 할 용도로 사용한다 이야기했다. 

 

필자의 설명이 부족할 것 같아 이고잉님이 정리하신 글을 다시 반복해서 올린다.

 

결론부터 말하면 SSL은 암호화된 데이터를 전송하기 위해서 공개키와 대칭키를 혼합해서 사용한다. 즉 클라이언트와 서버가 주고 받는 실제 정보는 대칭키 방식으로 암호화하고, 대칭키 방식으로 암호화된 실제 정보를 복호화할 때사용할 대칭키는 공개키 방식으로 암호화해서 클라이언트와 서버가 주고 받는다. 이 설명만으로는 이해하기 어려울 것이다. 아래의 관계만 일단 머리속에 기억해두고 좀 더 구체적인 설명으로 넘어가자.

  • 실제 데이터 : 대칭키
  • 대칭키의 키 : 공개키

컴퓨터와 컴퓨터가 네트워크를 이용해서 통신을 할 때는 내부적으로 3가지 단계가 있다. 아래와 같다.

악수 -> 전송 -> 세션종료

이것은 은밀하게 일어나기 때문에 사용자에게 노출되지 않는다. 이 과정에서 SSL가 어떻게 데이터를 암호화해서 전달하는지 살펴보자.

1. 악수 (handshake)

사람과 사람이 소통을 할 때를 생각해보자. 우선 인사를 한다. 인사를 통해서 상대의 기분과 상황을 상호탐색을 하는 것이다. 이 과정이 잘되야 소통이 원활해진다. 클라이언트와 서버 사이도 마찬가지다. 실제 데이터를 주고 받기 전에 클라이언트와 서버는 일종의 인사인 Handshake(진짜로 사용하는 기술용어다)를 한다. 이 과정을 통해서 서로 상대방이 존재하는지, 또 상대방과 데이터를 주고 받기 위해서는 어떤 방법을 사용해야하는지를 파악한다.

SSL 방식을 이용해서 통신을 하는 브라우저와 서버 역시 핸드쉐이크를 하는데, 이 때 SSL 인증서를 주고 받는다. 이 과정은 앞에서 설명한 바 있다. 인증서에 포함된 서버 측 공개키의 역할은 무엇일까를 이제 알아보자.

공개키는 이상적인 통신 방법이다. 암호화와 복호화를 할 때 사용하는 키가 서로 다르기 때문에 메시지를 전송하는 쪽이 공개키로 데이터를 암호화하고, 수신 받는 쪽이 비공개키로 데이터를 복호화하면 되기 때문이다. 그런데 SSL에서는 이 방식을 사용하지 않는다. 왜냐하면 공개키 방식의 암호화는 매우 많은 컴퓨터 자원을 사용하기 때문이다. 반면에 암호화와 복호화에 사용되는 키가 동일한 대칭키 방식은 적은 컴퓨터 자원으로 암호화를 수행할 수 있기 때문에 효율적이지만 수신측과 송신측이 동일한 키를 공유해야 하기 때문에 보안의 문제가 발생한다. 그래서 SSL은 공개키와 대칭키의 장점을 혼합한 방법을 사용한다. 그 핸드쉐이크 단계에서 클라이언트와 서버가 통신하는 과정을 순서대로 살펴보자.

  1. 클라이언트가 서버에 접속한다. 이 단계를 Client Hello라고 한다. 이 단계에서 주고 받는 정보는 아래와 같다.
    • 클라이언트 측에서 생성한 랜덤 데이터 : 아래 3번 과정 참조
    • 클라이언트가 지원하는 암호화 방식들 : 클라이언트와 서버가 지원하는 암호화 방식이 서로 다를 수 있기 때문에 상호간에 어떤 암호화 방식을 사용할 것인지에 대한 협상을 해야 한다. 이 협상을 위해서 클라이언트 측에서는 자신이 사용할 수 있는 암호화 방식을 전송한다.
    • 세션 아이디 : 이미 SSL 핸드쉐이킹을 했다면 비용과 시간을 절약하기 위해서 기존의 세션을 재활용하게 되는데 이 때 사용할 연결에 대한 식별자를 서버 측으로 전송한다.
       
  2. 서버는 Client Hello에 대한 응답으로 Server Hello를 하게 된다. 이 단계에서 주고 받는 정보는 아래와 같다.
    • 서버 측에서 생성한 랜덤 데이터 : 아래 3번 과정 참조
    • 서버가 선택한 클라이언트의 암호화 방식 : 클라이언트가 전달한 암호화 방식 중에서 서버 쪽에서도 사용할 수 있는 암호화 방식을 선택해서 클라이언트로 전달한다. 이로써 암호화 방식에 대한 협상이 종료되고 서버와 클라이언트는 이 암호화 방식을 이용해서 정보를 교환하게 된다.
    • 인증서
       
  3. 클라이언트는 서버의 인증서가 CA에 의해서 발급된 것인지를 확인하기 위해서 클라이언트에 내장된 CA 리스트를 확인한다. CA 리스트에 인증서가 없다면 사용자에게 경고 메시지를 출력한다. 인증서가 CA에 의해서 발급된 것인지를 확인하기 위해서 클라이언트에 내장된 CA의 공개키를 이용해서 인증서를 복호화한다. 복호화에 성공했다면 인증서는 CA의 개인키로 암호화된 문서임이 암시적으로 보증된 것이다. 인증서를 전송한 서버를 믿을 수 있게 된 것이다.

    클라이언트는 상기 2번을 통해서 받은 서버의 랜덤 데이터와 클라이언트가 생성한 랜덤 데이터를 조합해서 pre master secret라는 키를 생성한다. 이 키는 뒤에서 살펴볼 세션 단계에서 데이터를 주고 받을 때 암호화하기 위해서 사용될 것이다. 이 때 사용할 암호화 기법은 대칭키이기 때문에 pre master secret 값은 제 3자에게 절대로 노출되어서는 안된다.

    그럼 문제는 이 pre master secret 값을 어떻게 서버에게 전달할 것인가이다. 이 때 사용하는 방법이 바로 공개키 방식이다. 서버의 공개키로 pre master secret 값을 암호화해서 서버로 전송하면 서버는 자신의 비공개키로 안전하게 복호화 할 수 있다. 그럼 서버의 공개키는 어떻게 구할 수 있을까? 서버로부터 받은 인증서 안에 들어있다. 이 서버의 공개키를 이용해서 pre master secret 값을 암호화한 후에 서버로 전송하면 안전하게 전송할 수 있다.
     
  4. 서버는 클라이언트가 전송한 pre master secret 값을 자신의 비공개키로 복호화한다. 이로서 서버와 클라이언트가 모두 pre master secret 값을 공유하게 되었다. 그리고 서버와 클라이언트는 모두 일련의 과정을 거쳐서 pre master secret 값을 master secret 값으로 만든다. master secret는 session key를 생성하는데 이 session key 값을 이용해서 서버와 클라이언트는 데이터를 대칭키 방식으로 암호화 한 후에 주고 받는다. 이렇게해서 세션키를 클라이언트와 서버가 모두 공유하게 되었다는 점을 기억하자.
     
  5. 클라이언트와 서버는 핸드쉐이크 단계의 종료를 서로에게 알린다.

2. 세션

세션은 실제로 서버와 클라이언트가 데이터를 주고 받는 단계이다. 이 단계에서 핵심은 정보를 상대방에게 전송하기 전에 session key 값을 이용해서 대칭키 방식으로 암호화 한다는 점이다. 암호화된 정보는 상대방에게 전송될 것이고, 상대방도 세션키 값을 알고 있기 때문에 암호를 복호화 할 수 있다.

그냥 공개키를 사용하면 될 것을 대칭키와 공개키를 조합해서 사용하는 이유는 무엇을까? 그것은 공개키 방식이 많은 컴퓨터 파워를 사용하기 때문이다. 만약 공개키를 그대로 사용하면 많은 접속이 몰리는 서버는 매우 큰 비용을 지불해야 할 것이다. 반대로 대칭키는 암호를 푸는 열쇠인 대칭키를 상대에게 전송해야 하는데, 암호화가 되지 않은 인터넷을 통해서 키를 전송하는 것은 위험하기 때문이다. 그래서 속도는 느리지만 데이터를 안전하게 주고 받을 수 있는 공개키 방식으로 대칭키를 암호화하고, 실제 데이터를 주고 받을 때는 대칭키를 이용해서 데이터를 주고 받는 것이다.

3. 세션종료

데이터의 전송이 끝나면 SSL 통신이 끝났음을 서로에게 알려준다. 이 때 통신에서 사용한 대칭키인 세션키를 폐기한다.

 

 

HTTPS와 SSL 인증서 - 생활코딩

HTTPS VS HTTP HTTP는 Hypertext Transfer Protocol의 약자다. 즉 Hypertext 인 HTML을 전송하기 위한 통신규약을 의미한다. HTTPS에서 마지막의 S는 Over Secure Socket Layer의 약자로 Secure라는 말을 통해서 알 수 있듯이 보안이 강화된 HTTP라는 것을 짐작할 수 있다. HTTP는 암호화되지 않은 방법으로 데이터를 전송하기 때문에 서버와 클라이언트가 주고 받는 메시지를 감청하는 것이

www.opentutorials.org

여기까지 간단히 HTTP와 HTTPS의 차이점, HTTPS의 동작방법을 다루어보았다.

posted by 여성게
:
인프라/네트워크(기초) 2019. 8. 1. 16:07

 

오늘 다루어볼 포스팅 내용은 Wireshark를 이용한 네트워크 패킷 분석 예제입니다. HTTP/HTTPS 포스팅을 위한 선행 작업이라고 볼 수 있을 것 같습니다.

 

모든 환경은 Mac OS 환경에서 진행되었음을 알려드립니다.

 

 

Wireshark · Download

Riverbed is Wireshark's primary sponsor and provides our funding. They also make great products that fully integrate with Wireshark. I have a lot of traffic... ANSWER: SteelCentral™ Packet Analyzer PE • Visually rich, powerful LAN analyzer • Quickly access

www.wireshark.org

설치는 위 링크에서 진행합니다.

 

 

자신의 OS에 맞는 버전을 설치해줍니다.

 

 

실행화면입니다. 분석하길 원하는 것을 Capture 목록에서 선택하셔도 되고 위에 보이는 필터링을 통하여 분석하길 원하는 필터값을 채워줘도 됩니다. 저는 스프링부트 테스트 프로젝트를 실행하여 로컬로 들어오는 패킷을 분석하기 위하여 로컬IP와 프로토콜을 필터로 등록하였습니다.

 

 

요청을 하나 보낸 후 패킷을 살펴보았습니다. "POST /chat/ssl"이라는 요청으로 데이터를 보낸 예제입니다.

 

 

Form에 담아서 보낸 데이터를 직접 확인할 수 있습니다.

 

 

보시면 HTTP 프로토콜을 이용한 웹서비스는 굉장히 위험한 방법임을 알 수 있습니다. 누군가가 악의적인 목적으로 패킷분석을 하면 HTTP 같은 경우 Plain Text 형식으로 데이터가 넘어가 누구나 다 들여다 볼 수 있습니다. 이렇기 때문에 모든 웹서비스는 HTTPS라는 프로토콜을 이용해 모든 데이터를 암호화하여 서비스를 진행합니다. 해당 관련 포스팅은 추후에 올리도록 하겠습니다.

 

지금까지 와이어샤크 설치 및 와이어샤크를 이용한 간단한 패킷분석 예제를 살펴보았습니다. 사실 더 다양하게 필터링을 걸어서 원하는 네트워크 흐름만 분석이 가능합니다. 해당 옵션 및 사용법, 문법은 구글신께..

posted by 여성게
:
인프라/운영체제 2019. 7. 28. 18:55

2019/07/28 - [운영체제] - 운영체제 - 병행 프로세스란?

 

운영체제 - 병행 프로세스란?

2019/07/27 - [운영체제] - 운영체제 - 프로세스(Process)란? 프로세스상태,Context Switching 운영체제 - 프로세스(Process)란? 프로세스상태,Context Switching 프로세스의 개념 프로세스는 다양한 정의가 있다...

coding-start.tistory.com

 

이전 포스팅에서 병행 프로세스에 대해 간단히 개념을 다루어보았는데, 병행 프로세스에서 꼭 해결해야할 것 중 하나가 공유 자원에 대한 상호배제(동기화)였다. 오늘은 이런 상호배제에 대한 내용을 다루어볼 것이다.

 

상호배제의 개념

상호배제는 병행 프로세스에서 프로세스 하나가 공유 자원을 사용할 때 다른 프로세스들이 동일한 일을 할 수 없도록 하는 방법이다. 즉, 공유 자원에 있는 데이터에 접근하는 다른 프로세스를 이미 사용중인 프로세스 하나가 해당 데이터에 접근할 수 없게 하는 것을 상호배제(Mutual exclustion,Mutex)라고 한다. 물론 읽기 연산은 공유 데이터에 동시에 접근해도 문제가 발생하지 않지만, 변수나 파일은 프로세스 별로 하나씩 차례로 읽거나 쓰도록 해야한다. 예를 들면 하나의 프로세스가 순차적으로 파일을 읽는 작업을 하는 도중에 다른 프로세스가 파일의 내용을 변경해버리면 읽어오는 값이 예상과 다를 수 있기에 이러한 상황을 제어하는 동기화 작업이 필요한 것이다.

 

 

예를 들어 위의 그림에서 Thread A가 파일 쓰기 작업을 진행 중이다. 하지만 작업 도중에 Thread B가 파일을 읽기 위해 접근한다면 Thread B는 읽기 작업을 하지 못하고 대기하게 된다. 여기서 해당 파일(공유자원)을 가지고 주무르는 작업(코드)을 임계영역이라고 하고 먼저 해당 자원을 사용하는 임계코드를 실행중인 Thread A는 Lock(열쇠)을 손에 쥐게 된다. 그리고 그 이후에 Thread B가 접근하면 해당 스레드는 이미 Thread A가 Lock(열쇠)을 손에 쥐고 있기 때문에 임계영역에 접근할 수 없고 대기하게 되며 추후에 Thread A가 Lock(열쇠)를 반환하면 그때서야 Thread B가 임계영역에 진입할 수 있게 되는 것이다.

 

여기서 특징은 상호배제(Mutex)의 특징이 나온다. 바로 해당 자원에는 한순간 하나의 프로세스만 접근할 수 있기 때문에 Lock은 딱 한 프로세스에게만 쥐어주는 것이다. 또한 공유 자원을 사용하는 프로세스만 다른 프로세스를 차단하는 것을 알 수 있다.

 

<상호배제의 조건>

  1. 두 프로세스는 동시에 공유 자원에 진입할 수 없다.
  2. 프로세스의 속도나 프로세서 수에 영향을 받지 않는다.
  3. 공유 자원을 사용하는 프로세스만 다른 프로세스를 차단할 수 있다.
  4. 프로세스가 공유 자원을 사용하려고 너무 오래 기다려서는 안 된다.

 

여기서 임계영역은 어떤 전역 변수일 수도 있고 입출력을 위한 버퍼가 될 수도 있다. 이러한 임계영역을 이용하여 효과적으로 상호배제를 구현할 수 있는 것이다.

 

상호배제 방법들

상호배제를 해결하는 다양한 방법이 있다. 아래 표에는 상호배제를 구현하는 방법들을 정리해 놓은 것이다.

 

수준 방법 종류
고급 소프트웨어로 해결
  • 데커 알고리즘
  • 크누스 알고리즘
  • 램포트의 베이커리 알고리즘
  • 핸슨 알고리즘
  • 다익스트라 알고리즘
소프트웨어가 제공 : 프로그래밍 언어와 운영체제 수준에서 제공
  • 세마포어
  • 모니터
저급 하드웨어로 해결
  • TestAndSet(TAS)

 

모든 것을 다 다루어 보지는 않을 것이다. 몇 가지만 살펴보자.

 

<데커 알고리즘>

데커 알고리즘은 병행 프로그래밍의 상호배제 문제를 풀 수 있는 첫 번째 해결책으로 알려졌다. 두 프로세스가 동시에 임계영역에 진입하려고 시도하면 순서에 따라 오직 하나만 임계영역에 들어가도록 허용한다. 데커 알고리즘에서 각 프로세스는 플래그를 설정할 수 있고, 다른 프로세스를 확인한 후 플래그를 재설정할 수도 있다. 프로세스가 임계 영역에 진입하고 싶으면 플래그를 설정하고 차례를 기다린다. 즉, 임계 영역에 다른 프로세스가 이미 있으면 해당 프로세스를 종료할 때까지 while 문에서 순환한다. 여기서는 임계 영역 진입, 두 프로세스 간의 순서를 나타내는 turn 변수를 입력했다는 의미로 flag[0] 플래그와 flag[1] 플래그를 사용한다. 간단한 코드로 살펴보자.

 

======================데커 알고리즘 간단한 코드=========================
flag[0]=false;
flag[1]=false;
turn=0;

===================프로세스 P0 임계 영역 진입 코드=======================
//프로세스 P0의 임계 영역 진입 절차
flag[0]=true; //P0의 임계 영역 진입 표시
while(flag[1]==true){ //P1의 임계 영역 진입 여부 확인
	if(turn==1){ //P1이 임계영역에 진입할 차례가 되면
    	flag[0]=false; //플래그를 재설정하여 P1에 진입 순서 양보
        while(turn==1){ //P0이 임계영역에 진입할 차례가 될 때까지
        	//프로세스 P0의 바쁜 대기
        }
        flag[0]=true; //P1이 임계 영역에 진입할 차례가 되면 플래그 값 변경
    }
}

/*임계 영역 코드*/
turn=1; //임계 영역 코드 수행 이후 P1에게 진입 turn을 양보.
flag[0]=false;
/*나머지 코드 수행부분*/

===================프로세스 P1 임계 영역 진입 코드=======================
//프로세스 P1의 임계 영역 진입 절차
flag[1]=true;
while(flag[0]==true){
	if(turn==0){
    	flag[1]=false;
        while(turn==0){
        	//프로세스 P1의 바쁜 대기
        }
        flag[1]=true;
    }
}

/*임계 영역 코드*/
turn=0; //임계 영역 코드 수행 이후 P0에게 진입 turn을 양보.
flag[1]=false;
/*나머지 코드 수행부분*/
======================데커 알고리즘 간단한 코드=========================

 

상호배제 문제를 소프트웨어적으로 해결하는 데커 알고리즘의 특징

  • 특별한 하드웨어 명령문이 필요 없다.
  • 임계 영역 바깥에서 수행 중인 프로세스가 다른 프로세스들이 임계 영역에 들어가려는 것을 막지 않는다.
  • 임계 영역에 들어가기를 원하는 프로세서를 무한정 기다리게 하지 않는다.

 

<TestAndSet(TAS) 명령어>

공유 변수를 수정하는 동안 인터럽트 발생을 억제하여 임계 영역 문제를 간단하게 해결할 수 있지만, 이 방법은 항상 적용할 수 없고 실행 효율이 현저히 떨어진다. 또 소프트웨어적인 해결책은 더 복잡하고 프로세스가 2개 이상일 때는 더 많이 대기할 수 있다. 메모리 영역의 값에 대해 검사와 수정을 원자적으로 수행할 수 있는 하드웨어 명령이 TAS를 이용하여 간단한 방법으로 임계 영역 문제를 해결할 수 있다.

 

//target을 검사하고 target 값을 true로 설정
boolean TestAndSet(boolean *target){
	boolean temp=*target;
    *target=true;
    return temp;
}

//전역변수 영역(프로세스들의 공유변수들)
boolean waiting[n]; //배열을 선언함으로써 프로세스가 2개 이상와서 대기할 수 있도록 한다.
boolean lock=false;
int j; //0..n-1
boolean key;

do{ //프로세스 Pi의 진입 영역
	waiting[i]=true
    key=true;
    while(waiting[i]&&key){
    	key=TestAndSet(&lock);
    }
    waiting[i]=false;
    /*임계영역*/
    /*탈출영역*/
    
    j=(i+1)%n;
    while((j!=i)&&!waiting[j]){ //대기 중인 프로세스를 찾음
    	j=(j+1)%n;
    }
    if(j==i){ //대기 중인 프로세스가 없다면
    	lock=false; //다른 프로세스의 진입 허용
    }else{ //대기 중인 프로세스가 있으면 다음 순서로 임계 영역에 진입
    	waiting[j]=false; //Pj가 임계 영역에 진입할 수 있도록
    }
    //나머지 영역
}while(true);

 

프로세스 Pi의 진입 영역에서 waiting[i]가 true이므로 Pi는 임계 영역에 들어가려고 시도한다. 처음에 lock을 false로 초기화했다. 그러므로 임계 영역에 들어가는 첫 번째 Pi 프로세스는 TestAndSet(&lock)으로 key가 false가 되어 while문을 벗어 나게 되어 임계 영역을 진행한다. lock은 TestAndSet(&lock)으로 true가 되므로 다른 프로세스의 임계 영역 진입 코드의 while 문에서는 key가 true이기에 계속 while문에서 대기하게 된다. Pi가 임계 영역에 들어가기 전에 waiting[i]는 false로 설정하고 임계 영역으로 진입한다. 여기서 중요한 것은 lock이 true가 되어 다른 프로세스의 임계 영역 진입 코드의 while문에서 key가 true로 계속 반환되어 while 문에 머물고 있는 것을 기억해야한다.

Pi가 임계 영역을 떠날 때는 대기 프로세스 중에서 다음으로 진입할 수 있는 프로세스를 선택해야 한다. j=(i+1)%n; 코드로 차례가 높은 프로세스를 선택한 후 다음 while 문에서 각 프로세스를 검사한다. waiting 배열을 i+1,i+2,...n-1,0 순서로 조사하여 waiting 값이 true인 첫 번째 프로세스가 임계 영역으로 진입할 다음 프로세스가 된다.(임계 영역에 진입하기 위해 대기하는 프로세스는 임계 영역 초반 waiting[i]가 true가 된 상태로 while 문에서 대기중) 만약 대기 중인 프로세스가 없다면 lock을 false로 해제하고, 다음 프로세스가 Pj이면 임계 영역에 진입할 수 있도록 Pi는 waiting[j]를 false로 변경한다.(waiting[j]를 false로 변경하면 임계 영역을 진입하기 위해 대기중인 Pj가 while(waiting[j]&&key)에서 벗어 나게 되고 임계영역으로 진입한다.)

 

TestAndSet 명령어의 장단점

 

장점

사용자 수준에서 가능하다.

  • 메인 메모리를 공유하는 다중 프로세서나 단일 프로세서에서 프로세스 수에 관계없이 적용할 수 있다.
  • lock 변수 수에 상관없이 구현할 수 있다.
  • 구현이 단순하고 확인이 용이하다.
  • 다중 임계 영역을 지원한다.
단점

-바쁜 대기 발생

  • 프로세서 시산 소모가 크다.
  • 대기 프로세스는 비생산적, 자원이 소모되는 대기 루프에 남는다.

-기아 상태 발생 : 프로세스가 임계 영역을 떠날 때 프로세스 하나 이상을 대기하는 경우가 가능하다.

-교착 상태 발생 : 플래그는 우선순위가 낮은 프로세스가 재설정할 수 있지만, 우선순위가 높은 프로세스가 선점한다. 따라서 우선순위가 낮은 프로세스는 lock을 가지고, 우선순위가 높은 프로세스가 이것을 얻으려 시도할 때 높은 우선순위 프로세스는 무한정 바쁜 대기가 될 것이다.

 

<세모포어,semaphore>

앞서 제시한 상호배제의 해결 방법들은 좀 더 복잡한 문제에서는 일반화하기 어렵다. 또 프로세스가 임계 영역에 진입할 수 없을 때는 진입 조건이 true가 될 때까지 반복적으로 조사하고 바쁜 대기를 하게 되어 프로세스를 낭비한다. 진입 조건을 반복 조사하지 않고 true일 때 프로세스 상태를 확인한다면 프로세서 사이클을 낭비하지 않을 것이다. 다익스트라가 제안한 세모포어라는 동기화 도구는 상호배제 이외에도 다양한 연산의 순서도 제공한다.

 

세모포어는 값이 음이 아닌 정수인 플래그 변수이다.(음수 값을 가질 수 있는 세마포어는 음수 값을 할당하여 대기 중인 프로세스 갯수를 알고 처리하는 방법이 있다고는 하는데..음수가 되는 순간 해당 프로세스는 대기큐에 넣은 후에 S가 0보다 커지는 순간 대기큐에서 가져와 임계영역 코드를 수행시키는 원리.) 또한 P와 V 연산과 관련되어 있고 세마포어를 의미하는 S라는 변수를 갖는다. 임계 영역에 진입하는 프로세스는 P연산(wait)을 수행하여 S>=0이라면 S값을 하나 감소시키고 임계영역에 들어가고 만약 S<=0이라면 S값을 하나 감소시키고(S값이 음수로 된다) 대기큐로 들어간다.(지속적으로 S>=0일때가지 반복문을 도는 것이 아니라 대기 큐에 들어가 멈춰있는 상태-sleep가 된다. 바쁜 대기 문제 해결) 그리고 임계영역의 코드를 모두 수행하면 V연산(signal)로 S값을 하나 증가시키고 S값이 0보다 커지면 대기큐에서 sleep 중인 프로세스를 깨우는 행동을 하게 된다.

 

<Info>

음수 값을 가질 수 없는 세마포어는 뮤텍스와 같이 바쁜대기가 발생한다. 하지만 음수를 가지는 세마포어는 대기큐에 프로세스를 중단시킨 상태로 넣어놓으니 바쁜 대기가 발생하지 않는다.

바쁜 대기 : 자원을 사용할 수 있는 상태인지 반복해서 체크

 

P,V 연산은 운영체제가 실행하고, 임의의 프로세스가 시스템 호출을 하는 것이다.

 

P(S) : wait(S){
		S -> count--;
	    if(S -> count < 0) {
        	add this process to S -> queue; //프로세스를 준비 큐에 추가
            block(); //프로세스 중단(일시정지)
		}
	   }
       
V(S) : signal(S){
       		S -> count++;
            if(S -> count > 0){
            	remove a process P from S -> queue; // 준비 큐에서 P 프로세스 제거
                wakeup(P); //신호를 보내 프로세스를 실행
            }
	   }

 

P와 V 연산에 있는 세마포어 S의 정수 값 변경은 개별적으로 실행하고, 누군가가 이 연산을 수행하고 있다면 다른 프로세스는 해당 연산을 수행할 수 없다. 즉, P,V 연산이 다른 프로세스들이 동시에 할 수 없도록 조정해야한다. 여기서 일반 상호배제(뮤텍스)와는 조금 다른 것이 S값을 1보다 큰 값으로 초기화하여 여러 프로세스가 동시에 임계 영역을 진입하게 할 수 있다는 것이다.(S값만큼 공유 영역을 만들어서 각각의 공유 영역에 서로 다른 프로세스를 통과시킬 수 있다.)

 

즉, S가 1로 초기화된다면 바이너리 세마포어, S가 1보다 크다면 계수형 세마포어가 된다. 밑의 그림은 계수형 세마포어가 된다.

 

그렇다면 세마포어와 뮤텍스의 차이점을 무엇일까? 기본적인 차이점을 세마포어는 시그널링 메커니즘이라는 것이다. 즉, 프로세스는 wait() 및 signal() 작업을 수행하여 자원 획득 또는 해제여부를 나타낸다. 뮤텍스는 잠금 메커니즘이며, 프로세는 Lock을 획득해야한다. 아래는 세마포어와 뮤텍스의 차이점을 정리해 놓은 표이다.

 

세마포어 뮤텍스
세마포어는 시그널링 메커니즘이다. 뮤텍스는 잠금 메커니즘이다.
세마포어는 정수 변수이다. 뮤텍스는 Object이다.
세마포어는 여러 프로세스가 여러 유한한 자원에 액세스할 수 있게 한다. 뮤텍스는 여러 프로세스가 단일 리소스에 액세스할 수 있지만 동시에 수행할 수 없게 한다.
세마포어 값은 자원을 얻거나 해제하는 프로세스에 의해 변경 될 수 있다. 뮤텍스 Lock은 반드시 획득한 프로세스에 의해서만 해제된다.
세마포어는 계수형(count) 세마포어와 바이너리 세마포어로 분류된다. 더 이상의 분류는 없다.
세마포어 값은 wait() 및 signal() 연산을 사용하여 수정된다. 리소스를 요청하거나 해제하는 프로세스에 의해 Lock&Unlock이 된다.
모든 리소스가 사용 중이면 리소스를 요청하는 프로세스는 wait() 작업을 수행하고 대기큐에 들어가 있으면서 세마포어 값이 1이상이 될때 다른 프로세스에 의해 wakeup한다. Lock이 걸려있으면 Lock의 소유 프로세스가 잠금을 풀때까지 프로세스가 대기하고 있는다(바쁜 대기)

 

<모니터>

세마포어는 상호배제와 프로세스 사이를 조정하는 유연성 있고 강력한 도구이지만 wait&signal 연산 순서를 바꿔 실행하거나 둘 중 하나 이상을 생략하면 상호배제를 위반하거나 교착 상태가 발생한다. wait과 signal 연산이 프로그램 전체에 퍼져 있고 이들 연산이 각 세마포어에 주는 영향을 전체적으로 파악하기가 쉽지 않기에 세마포어를 잘못 사용하면 여러 가지 오류가 쉽게 발생하여 프로그램을 작성하기가 어렵다. (즉, 타이밍 문제가 발생할 수 있다.)모니터는 이러한 단점을 극복하려고 등장하였다.

 

모니터의 개념과 구조

모니터는 프로그래밍 언어 수준에서 제공해준다. 모니터를 사용하여 상호배제를 하는 예제로는 Java 언어가 있다.

 

 

프로세스들은 모니터의 프로시저를 호출하여 모니터 안에 진입한 후 지역(공유) 데이터에 접근할 수 있다. 무엇보다 언제나 한 번에 프로세스 하나만 모니터에 진입할 수 있도록 제한하여 상호배제를 실현한다는 것이 중요하다. 만약 다른 프로세스가 모니터를 점유하고 있으면 프로세스는 외부의 모니터 준비 큐에서 진입을 기다리게 되어 상호배제를 실현한다. 위에서 초기화 코드는 모니터를 생성할 때 한번 사용된다.

 

또한 중요한 개념중 하나가 조건 변수이다. 특정 조건이 부합하지 않아 모니터 실행 도중 cwait(c1)을 호출한 프로세스는 모니터 내부의 조건 c1 준비큐에 들어가 대기한다. 그리고 새로운 프로세스가 모니터 안에서 수행을 진행하고 해당 프로세스가 c1.signal을 호출하면 c1 대기 큐에 있던 프로세스가 중단되어 있다 다시 실행하러 들어온다. 즉, 단순히 세마포어처럼 signal 연산을 보내는 것이 아니라 특정 조건 대기큐에 대한 signal을 보내 작업을 시작시키는 것이다.

 

예를 들어 프로세스 하나가 모니터 내부에서 임계영역 코드를 수행하고 c1에 시그널을 보내면 모니터 내부에 있는 c1 준비큐에서 프로세스 하나가 나와 임계영역 코드에 진입하고, 만약 조건 signal을 보내지 않고 빠져 나온다면 외부에 있는 큐중에 한 프로세스를 꺼내어 임계영역에 진입시킨다. 물론 c1 시그널을 보냈는 데 c1에 대기하고 있는 프로세스가 없다면 아무런 효과가 없어 외부에 있는 대기 큐에서 프로세스를 꺼내온다.

 

Java의 wait(),notify(),notifyAll()이 모니터를 사용하기 위한 조건 변수라고 볼 수 있다. 모니터 내부에서 wait()을 호출하면 모니터 내부에 있는 WaitSet에 들어가 중단된 상태로 대기하고 있는 상태가 되는 것이고 누군가가 notify(),notifyAll()을 호출하면 모니터 내부에 있는 WaitSet에 있는 프로세스중 하나를 실행상태로 만들어주는 것이다. 물론 synchronized가 걸려 모니터 내부에 들어오지 못한 프로세스(스레드)들은 EntrySet이라는 외부 준비큐에 들어가 있는 상태가 되는 것이다.

 

 

 

-참조

 

Difference Between Semaphore and Mutex (with Comaprison Chart) - Tech Differences

The basic difference between semaphore and mutex is that semaphore is a signalling mechanism i.e. processes perform wait() and signal() operation to indicate whether they are acquiring or releasing the resource, while Mutex is locking mechanism, the proces

techdifferences.com

 

 

Difference Between Semaphore and Monitor in OS (with Comparison Chart) - Tech Differences

Semaphore and Monitor both allow processes to access the shared resources in mutual exclusion. Both are the process synchronization tool.

techdifferences.com

 

posted by 여성게
: