AWS

클라우드를 시작하는 사람을 위한 안내서

시작하는 사람을 위한 안내서를 작성하고 싶었는데, 좀 늦었다.

매번 하는 말이지만 내 게으름 때문이다.
꼭 누군가에게 도움이 되는 글을 작성하고 싶었는데 그게 바로 오늘인 듯 하다.

클라우드를 하려면 먼저 계정을 생성하여야 한다.

계정을 생성 하였는가? 축하한다. 드디어 클라우드에 입문한 셈이다.

Twitter 上的 DRX|KNEE:"일리단님의 말이 떠오르는 어제 하루였다 아직 준비가 안됐다  https://t.co/QjLPBqUo64" / Twitter

클라우드는 보통 웹 콘솔로 처음 접하게 된다.
CSP 에서 제공하는 웹사이트에 가입을 했다면 뭘 해야 할지 고민이 될 것이다.

모든 설명은 AWS를 기준으로 작성된다.

걱정 마라.

처음 가입하면 뭘해야 할지 바로 알려주겠다.

  1. MFA
  2. Budget
  3. Root 계정 봉인

3가지의 조치가 왜필요한지 이야기해 보겠다.

먼저 MFA를 하지 않아 털리게된다면 공격자는 AWS Console을 편하게 이용할 수 있다. 걸리기 전까지 컴퓨팅을 마음껏 쓸수 있는것이다. 이렇게 털린 계정은 전적으로 사용자 과실이다.

길바닥에 떨어진 지갑은 일반적인 사회라면 경찰서에 가져다주고 주인을 찾아 주겠지만, 그렇지 않은 경우도 많다. 그 길바닥에 떨어진 지갑이 바로 당신의 클라우드 계정이다. 작게는 수백 크게는 수억원까지 비용이 발생할수 있다. 이러한 대 참사를 막기위한 조치이다.

루트계정의 MFA를 설정하여 접근을 막고, 예산을 설정하여 비용이 초과되면 알럿을 받고, 루트계정을 사용하지 않는 방법과 역할 전환을 이용하여 계정의 보안을 강화하는 방법이 가장 적절한 방법인것이다. 여기에 리소스가 생성되면 알림을 받는것도 좋고, 사용하지 않는 태그를 기반으로 리소스가 생성되면 자동으로 삭제하는 방식도 좋다. 이런 여러가지 방식들이 있지만 가장 기본적인 방법이 위에서 제시한 세가지의 방법이다. 그럼 바로 시작하겠다.

MFA

라온클님 역작

MFA를 생성하기 전에 먼저 물어볼것이 있다. 혹시 메일주소가 다른 계정이나, 패스워드가 겹치진 않는가?
이건 굉장히 중요한 문제다. 계정이 다른 아이디 나 패스워드가 겹친다면 삭제하고 처음부터 다시 만들자. 자주사용하는 아이디와 패스워드는 유출될 확률이 높다. 물론 MFA를 사용하면 안전하다. 하지만 언제나 방심하는 순간 문제가 발생한다. 그러니, 콘솔용 메일주소는 별도로 사용하는것이 좋다.

이제 그럼 MFA를 걸어보자.

IAM 서비스로 이동한다 Root 계정의 MFA도 IAM에서 설정할수 있다.

MFA는 사용하지 않으면 IAM 대시보드에 바로 경고가 떠있다. MFA 를 생성하자.

가상 MFA 디바이스를 선택한다.

MFA는 여러 어플이 있는데 나는 MS에서 만든 어플을 선호한다. 온라인백업 기능을 지원한다. QR코드 표시 누르고 그이미지를 백업해두어도 나중에 MFA를 다시추가 가능하다. 하지만 보안이 매우 좋지않음으로 추천하지 않는 방법이다. 보관하려면 압축후 비밀번호를 걸어서 보관하라.

연속된 MFA를 입력하라는건 6자리를 두번 입력해야한다.

두번 입력하면 MFA 설정이 완료된다.

이 쉬운 과정이 일단 그대의 콘솔이 털리는걸 막아주는거다. 로그인이 불편하더라도 꼭 사용하길 바란다.

Budget

Budget 설정은 결제 대시보드에 있다.

예산은 설정하면 알럿이 온다. 예산을 작성하도록 하자.

예산 관련 옵션 들은 FinOps를 위한 여러가지 기능을 제공하는데 우리는 그냥 비용 예산을 작성하면 된다.

일별로 변경후 5$를 설정한다 프리티어에서 하루 5$를 넘으면 대참사다. 한번 만들고 알럿이 귀찮으면 서서히 조정하자.

이메일 수신자에 받고싶은 이메일을 넣어도 되고 SNS 에 주제와, 구독을 생성하여 SMS등으로 받을수도 있으며, Chatbot Alerts를 이용하여 슬랙등 여러 Bot으로 알럿을 받을수 있다. 이메일은 무료고 뒤의 두가지는 비용이 발생할수 있으므로 메일로 받고 관리해야하는 서비스라면 봇이나 SNS를 이용하길 바란다.

이후 예산을 작성하면 이제 일정이상 비용이 넘으면 알럿이 발생한다.

벌써 두가지의 조치를 했다. 남은 두가지만 하면된다.

Root 계정 봉인

Root 계정은 많은 참사를 불러 온다. 이 대 참사를 막기위한 방법이 있다. Root 계정에 MFA를 걸어서 안전하다고 생각할지 모르나, 문제는 언제 어디서 발생할지 모른다. 그렇기에, Root 계정을 봉인하는것을 추천한다.

Root 계정을 사용하지 않고 어떻게 AWS를 안전하게 사용하는지 알려주겠다.

이 방법에는 두가지가 필요하다.

  1. IAM User
  2. IAM Role

먼저 로그인 통로가 될 User를 생성한다. IAM에서 사용자를 추가하면 된다.

IAM 서비스로 이동하고 사용자탭으로 이동해서 사용자 추가를 누른다.

액세스키 방식이 아닌 AWS 관리 콘솔 액세스를 선택한다.

이 계정엔 아무 권한도 주지 않을 것이다.

이렇게 나와야한다. 계정을 생성 완료 했다면 계정의 요약에서 보안 자격 증명을 눌러보자.

콘솔 로그인 링크로 로그인하기 전에 먼저해야할 것이 있다.

MFA다.(궁서체다 매우진지하므로 추가해라.)

MFA는 최대한 활용한다.

이상태가 되면된다. 이제 요약에서 보여주는 콘솔링크로 AWS를 이용한다. 한번 로그인해보시라.

이 아무 권한도 없는 계정은 이제 방파제가 되어 로그인을 제어해줄것이다. 권한이 없는 계정으로 뭘하는지 궁금할것이다. 이때 필요한것이 역할 전환이다. 그럼 IAM Role을 생성하자.

IAM에서 역할탭으로 이동한다. 역할 만들기를 누르자.

다음과 같이 체크해준다.

권한은 여기서 최대 권한을 주지만, 사용자에 맞게 권한을 주는것이 더 적절하다.

역할을 생성하고 이 역할을 사용할수 있도록 수정을 해야한다.

여기서 "arn:aws:iam::00000000000:root" 를 수정해야한다. 수정할 값은 아까만든 계정의 ARN이다. 사용자탭으로 이동해서 계정을 눌러보면

다음과 같이 ARN을 확인할수 있다. 하지만 ARN은 규칙이 있어서 보지않고 그냥 수정해도 된다. 다시 역할로 돌아와서

신뢰관계를 수정하면 이제 생성했던 계정이 이 역할을 사용할수있다. 덤으로 MFA가 활성화 되어야지 만 이 역할을 사용할수 있다.

그럼이제 이 역할을 사용하는 방법은 바로전에 생성한 계정으로 로그인하고, 생성한 역할의 요약 탭에서 보여주는 역할전환 링크를 통해 역할을 전환한다.

다음메뉴에서 역할의 세션지속기간을 설정할수 있다. 역할전환 링크로 이동하면

다음과 같은 화면을 마주하게 되고, 역할 전환을 누르면 이제 IAM 사용자가 역할전환을 이용하여 AdministratorAccess 권한을 승계받은거다. 이제 해커는 MFA를 획득 하더라도 역할전환을 하지 못하면 어떠한 행위도 할 수 없다.

일반적으로 이 방식은 타 계정에서 어카운트를 생성하지 않고 로그인할때 사용하는 방식이다. 혹시 관리계정이 있다면 그관리계정에서 역할전환을 하는것이 더욱 권장되는 방식이다.

이외에도

https://aws.amazon.com/ko/premiumsupport/knowledge-center/config-email-resource-created/

AWS Config 서비스를 이용한 리소스 생성시 추적기능이 있다. 이 부분은 나중에 자세하게 다루어 볼까한다.

SNS EventBridge Config 등의 서비스를 사용하기때문이다.

이 글을 적게된 이유는 최근 여러 커뮤니티를 달군 3억 과금 때문이다. 해킹을 막기 위해선 불편함을 감수해야한다.

편하려다 피눈물 날테니 조심하자.

AWS Certified Data Analytics - Specialty - DAS-C01 - Review

Data Analytics 까지 시험을 봤습니다.

이 사태의 원인은 세웅님이었습니다.
치명적인 속도로 AWS 자격증을 클리어하는 것이 제가 나태한것 같이 느껴졌습니다.

그래서 MLS를 끝내고 DAS를 바로 시작했습니다.

DAS는 DBS-DAS-MLS 순으로 보면 좋은시험 같았습니다.

DAS는 주로 ETL 과 Analytics에 관련한 문제가 나옵니다.

https://jayendrapatil.com/aws-certified-data-analytics-specialty-das-c01-exam-learning-path/

제 블로그를 봐온 분들이라면 다들 아시겠지만 저는 jayendra 님의 블로그로 먼저 시험을 준비합니다. 도메인 분리도 잘되어있고, 요약정리가 정말 깔끔하기 때문입니다.

요약정리를 다 읽고 AWS에서 주로 사용할 서비스에 대한 이해가 필요합니다.

kinesis stream와 firehose 의 차이를 알면 정말 편해집니다.

firehose는 거의 실시간으로 동작하는 실은 1분마다 동작하는 batch 에 가깝습니다.

또 너무 비싸서 사용해볼수 없는 redshift는 경험을 쌓기 너무 어려우므로 docs가 닳도록 읽었습니다.

그외엔 사실 AWS에 익숙하다면 반쯤은 상식으로 먹고 들어가는 내용들이 많기때문에
-SAP를 취득하지 않았다면 먼저 취득하고 오십시오...(?) -
-DBS를 취득하지 않았다면 먼저 취득하고 오십시오...(?) -
아직 SAP가 없는 상태라면 SAP취득을 추천합니다.

실제로 시험은 모르는 내용이 아주 많았습니다.

하지만 풀수는 있었습니다. 샤딩이 뭔지 파티셔닝이 뭔지 ETL이 뭔지 등등 기본적인 개념들을 알고있다면 질문하는 의도와 정답을 알수있기 때문입니다.

예를 들어 stram 과 firehose 를 비교하게 되는 문제에서 실시간인지 거의 실시간인지만 파악할수 있다면 선택지를 하나를 줄일수 있게 되는것입니다. - 이것이 시험공학-

이번에 연습시험을 보려고 하니, 결제가 되지않았습니다. 바우처는 발급이 되었는데..

이젠 바우처를 사용하지 않아도 연습시험을 볼수있습니다.

AWS 에서 제공하는 무료 연습시험 모음집
11가지 시험의 연습문제를 제공해줍니다.

이렇게요!

DAS 연습문제를 각잡고 풀어본결과 70%가 나왔습니다.

시험은 미루지않는 것이 지론이고 떨어지면 칼을갈아서 다시 보면 되는거지만 벼랑끝에 매달린 심정으로 안되는 공부를 억지로 이어갔습니다.

그리고 오늘 오전일찍 시험을 봤습니다.

두구두구두구구두구 827점으로 통과.

그런데 이게 조금 아쉽긴 합니다. 만반의 준비를해서 시험이 수월하지않고, 요령으로 푼문제가 많아서 조금 아쉬웠습니다. 그렇지만 꼭 해내고 싶었고 자격증을 취득하였습니다.

2017년11월 부터 시작해서 2022년 1월까지의 장점이 마무리되었습니다.

제글을 읽어주셔서 감사합니다.

AWS Certified Machine Learning - Specialty - MLS-C01 - Review

오랜만의 자격증 글입니다.

최근에 책한권을 추천받았습니다.

기계학습을 다시묻다 라는 책이었습니다.
이광근 교수님의 번역에 대한 생각과 이해를 볼수있는 책이었습니다.

이 책을 읽으면서 너무너무너무너무 이해가 안갔습니다.
그 동안 머신러닝을 지속적으로 찍먹을 하던터라 읽을만 하지 않을까? 했는데 아니나 다를까 수포자에겐 자비가 없었습니다.

그렇지만, 근일년간 쿠버네티스와 머신러닝을 찍먹하면서 내가 머신러닝을 실무에 적용하고 쓸수있는 레벨은 아니지만 어떤기술이 어디서 사용된다 정도는 이해하고 있던터라 한번 과감하게 시험날자를 잡았습니다.

등급: Specialty
시간: 시험 완료까지 180분 소요
비용: 300 USD 

형식: 65개 문항, 다항 선택 또는 복수 응답
제공 방법: Pearson VUE 및 PSI. 테스트 센터 또는 온라인 유감독 시험

12월 24일 아침9 시 였습니다.

저의 시험의 시작은 보통 Jayendra 님의 블로그입니다.

https://explore.skillbuilder.aws/learn/course/external/view/elearning/27/exam-readiness-aws-certified-machine-learning-specialty

AWS에서 제공하는 연습시험 준비

https://docs.aws.amazon.com/ko_kr/sagemaker/latest/dg/algos.html

Sagemaker의 알고리즘표

기본적으로 AWS Docs/FAQ 찬찬히 여러번 읽는것부터 추천
저는 sagemaker의 핸즈온을 해본적이 있고, AWS에 익숙한 편이라 알고리즘 부분을 빼면 대부분 아주 수월하게 읽을 수 있었습니다.

jayendra 님의 정리된 내용이 너무 간결하고 좋아서 깊이있는 이해나 UI에서 어떤것들을 지원하는지 보면됩니다.

그리고 대망의 22일 연습시험을 봤습니다.

아아…그런건가 현대차.. - 주식 게시판 - 에펨코리아
 Jeong Taehwan님, 안녕하세요?
 AWS Certified Machine Learning - Specialty Practice 시험에 응시해 주셔서 감사합니다. 다음 정보를 살펴보고 준비가 더 필요한 주제를 확인하십시오.
총점: 55%
주제별 채점:
1.0  Data Engineering: 100%
2.0  Exploratory Data Analysis: 60%
3.0  Modeling: 25%
4.0  Machine Learning Implementation and Operations: 75%

아아..이것이 탈락의 느낌인가..

예..22일 연습시험이 55%로 너무 불안했습니다.

그리고 그 다음날은 약속도 있어서 예상한 만큼 공부를 할수있을지도 몰랐습니다.

그 약속의 감동

그 불안감이 점점 커져가며 저를 긴장하게 만들었고, 집중할수 없는 순간에도 알고리즘을 찾아보며, 내가 뭘모르는지를 이해하기 위해 힘썼습니다. 그리고 시험은 AWS 오프라인 시험을 봤습니다.

결과는!!

894점으로 합격할수 있었습니다.

AWS Certified Machine Learning - Specialty 배지

이로서 AWS의 10번째 자격증을 획득하였습니다.

읽어주셔서 감사합니다.

EKS-prometheus-grafana

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/prometheus.html

먼저 프로메테우스를 설치한다.

cat << EOF | k apply -f -
 ---
 apiVersion: v1
 kind: PersistentVolumeClaim
 metadata:
   name: grafana-pvc
 spec:
   accessModes:
     - ReadWriteOnce
   resources:
     requests:
       storage: 1Gi
 ---
 apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
     app: grafana
   name: grafana
 spec:
   selector:
     matchLabels:
       app: grafana
   template:
     metadata:
       labels:
         app: grafana
     spec:
       securityContext:
         fsGroup: 472
         supplementalGroups:
           - 0
       containers:
         - name: grafana
           image: grafana/grafana:7.5.2
           imagePullPolicy: IfNotPresent
           ports:
             - containerPort: 3000
               name: http-grafana
               protocol: TCP
           readinessProbe:
             failureThreshold: 3
             httpGet:
               path: /robots.txt
               port: 3000
               scheme: HTTP
             initialDelaySeconds: 10
             periodSeconds: 30
             successThreshold: 1
             timeoutSeconds: 2
           livenessProbe:
             failureThreshold: 3
             initialDelaySeconds: 30
             periodSeconds: 10
             successThreshold: 1
             tcpSocket:
               port: 3000
             timeoutSeconds: 1
           resources:
             requests:
               cpu: 250m
               memory: 750Mi
           volumeMounts:
             - mountPath: /var/lib/grafana
               name: grafana-pv
       volumes:
         - name: grafana-pv
           persistentVolumeClaim:
             claimName: grafana-pvc
 ---
 apiVersion: v1
 kind: Service
 metadata:
   name: grafana
 spec:
   ports:
     - port: 3000
       protocol: TCP
       targetPort: http-grafana
   selector:
     app: grafana
   sessionAffinity: None
   type: LoadBalancer
 EOF

https://grafana.com/docs/grafana/latest/installation/kubernetes/

설치는 위링크를 참조하고 grafana svc type 만 LoadBalancer 로 변경한다.

k get svc
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)          AGE
grafana      LoadBalancer   172.20.237.228   af7fa7486f6eb4ad4a6bde897210f4a9-206885623.ap-northeast-2.elb.amazonaws.com   3000:32317/TCP   32m

그라파나의 서비스가 다만들어지면 URL로 접근이 가능하다.

패스워드는 admin / admin 이다.

로그인후 할일은 data source 를 지정하는것이다. 우리는 prometheus 를 이용할것이다.

서비스이름/네임스페이스/svc:port 로 지정한다.

save & test 눌러서 잘되는지 확인하자.

그리고 dashboard를 import 하자.

https://grafana.com/grafana/dashboards/11074

많은 사람이 애용하는 dashboard를 사용할것이다. import 는 ID로 넣으면된다 이경우엔 11074 를 입력하자

VictoriaMetrics 를 프로메테우스로 지정하자. 그리고 Import 하면 대시보드가 뜬다.

대략 이런 대시보드가 자동으로 수집된다.

https://grafana.com/grafana/dashboards/13770

그라파나는 사람들이 만들어놓은 대시보드를 이용하기 쉽다.

그리고 node-exporter 로 만들어내는 매트릭리스트를 파악하여 원하는 지표를 사용할수 있다.

https://prometheus.io/docs/guides/node-exporter/

위URL을 참고해서 매트릭을 확인하여 보자.

예를 들어서 Dropped packet를 확인하려 한다면 다음 매트릭을 확인할수 있다.

읽어주셔서 감사하다!

올해의 가시다님 과의 스터디가 마무리되었다. 같이 EKS 스터디에 참여해주신분들께 감사를 드리며, 평안한 하루되시라!

AKOS-Study-Manual-EKS-istio

클러스터를 먼저 프로비저닝 했다. 30분이상이 걸리는 작업이므로 시작해놓고 기다린다.

eksctl create cluster --vpc-public-subnets $WKSubnets --name $CLUSTER_NAME --region $AWS_REGION --version 1.21 \
> --nodegroup-name $CLUSTER_NAME-nodegroup --node-type t3.medium --nodes 3 --nodes-min 3 --nodes-max 6 \
> --with-oidc --node-volume-size=20 --ssh-access --ssh-public-key $MySSHKeypair
2021-09-04 11:29:11 [ℹ]  eksctl version 0.63.0
2021-09-04 11:29:11 [ℹ]  using region ap-northeast-2
2021-09-04 11:29:12 [✔]  using existing VPC (vpc-094808933b68add7c) and subnets (private:map[] public:map[ap-northeast-2a:{subnet-0a603a222db0cce10 ap-northeast-2a 10.0.11.0/24} ap-northeast-2b:{subnet-007964ce4a003361a ap-northeast-2b 10.0.12.0/24} ap-northeast-2c:{subnet-007813cf58631ef3b ap-northeast-2c 10.0.13.0/24}])
2021-09-04 11:29:12 [!]  custom VPC/subnets will be used; if resulting cluster doesn't function as expected, make sure to review the configuration of VPC/subnets
2021-09-04 11:29:12 [ℹ]  nodegroup "first-eks-nodegroup" will use "" [AmazonLinux2/1.21]
2021-09-04 11:29:12 [ℹ]  using EC2 key pair %!q(*string=<nil>)
2021-09-04 11:29:12 [ℹ]  using Kubernetes version 1.21
2021-09-04 11:29:12 [ℹ]  creating EKS cluster "first-eks" in "ap-northeast-2" region with managed nodes
2021-09-04 11:29:12 [ℹ]  will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup
2021-09-04 11:29:12 [ℹ]  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-2 --cluster=first-eks'
2021-09-04 11:29:12 [ℹ]  CloudWatch logging will not be enabled for cluster "first-eks" in "ap-northeast-2"
2021-09-04 11:29:12 [ℹ]  you can enable it with 'eksctl utils update-cluster-logging --enable-types={SPECIFY-YOUR-LOG-TYPES-HERE (e.g. all)} --region=ap-northeast-2 --cluster=first-eks'
2021-09-04 11:29:12 [ℹ]  Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "first-eks" in "ap-northeast-2"
2021-09-04 11:29:12 [ℹ]  2 sequential tasks: { create cluster control plane "first-eks", 3 sequential sub-tasks: { 4 sequential sub-tasks: { wait for control plane to become ready, associate IAM OIDC provider, 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/aws-node", create serviceaccount "kube-system/aws-node" }, restart daemonset "kube-system/aws-node" }, 1 task: { create addons }, create managed nodegroup "first-eks-nodegroup" } }
2021-09-04 11:29:12 [ℹ]  building cluster stack "eksctl-first-eks-cluster"
2021-09-04 11:29:12 [ℹ]  deploying stack "eksctl-first-eks-cluster"
2021-09-04 11:29:42 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:30:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:31:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:32:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:33:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:34:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:35:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:36:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:37:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:38:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:39:12 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:40:13 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:41:13 [ℹ]  waiting for CloudFormation stack "eksctl-first-eks-cluster"
2021-09-04 11:45:14 [ℹ]  building iamserviceaccount stack "eksctl-first-eks-addon-iamserviceaccount-kube-system-aws-node"
2021-09-04 11:45:14 [ℹ]  deploying stack "eksctl-first-eks-addon-iamserviceaccount-kube-system-aws-node"

EKS를 Setup 하는 과정에 대해선 이전포스팅을 참고하기 바란다.

간단한 실습이 있지만..음 istio는 못참지.

가즈아!

먼저 istioctl을 설치하자.

curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.10.4 TARGET_ARCH=x86_64 sh -
tree istio-1.10.4/ -L 2
mv istio-1.10.4/bin/istioctl /usr/local/bin/istioctl
istioctl version

버전과 상황에 따라 설치 방법이 다를 수 있다.

istioctl install --set profile=demo -y

demo로 프로파일을 설정하게되면 istio에서 사용하는 모든 오브젝트를 설치해준다. 그러므로 만약 프로덕션에서 사용한다면 원하는 오브젝트만 따로 설치하자.

nginx pod에 istio inject 명령어로 yaml 에 istio를 주입하면 이렇게 된다.

#전
apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
#후    
istioctl kube-inject -f pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/default-container: nginx
    kubectl.kubernetes.io/default-logs-container: nginx
    prometheus.io/path: /stats/prometheus
    prometheus.io/port: "15020"
    prometheus.io/scrape: "true"
    sidecar.istio.io/status: '{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null}'
  creationTimestamp: null
  labels:
    istio.io/rev: default
    security.istio.io/tlsMode: istio
    service.istio.io/canonical-name: pod1
    service.istio.io/canonical-revision: latest
  name: pod1
spec:
  containers:
  - image: nginx
    name: nginx
    ports:
    - containerPort: 80
    resources: {}
  - args:
    - proxy
    - sidecar
    - --domain
    - $(POD_NAMESPACE).svc.cluster.local
    - --serviceCluster
    - pod1.default
    - --proxyLogLevel=warning
    - --proxyComponentLogLevel=misc:error
    - --log_output_level=default:info
    - --concurrency
    - "2"
    env:
    - name: JWT_POLICY
      value: third-party-jwt
    - name: PILOT_CERT_PROVIDER
      value: istiod
    - name: CA_ADDR
      value: istiod.istio-system.svc:15012
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: INSTANCE_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: SERVICE_ACCOUNT
      valueFrom:
        fieldRef:
          fieldPath: spec.serviceAccountName
    - name: HOST_IP
      valueFrom:
        fieldRef:
          fieldPath: status.hostIP
    - name: CANONICAL_SERVICE
      valueFrom:
        fieldRef:
          fieldPath: metadata.labels['service.istio.io/canonical-name']
    - name: CANONICAL_REVISION
      valueFrom:
        fieldRef:
          fieldPath: metadata.labels['service.istio.io/canonical-revision']
    - name: PROXY_CONFIG
      value: |
        {}
    - name: ISTIO_META_POD_PORTS
      value: |-
        [
            {"containerPort":80}
        ]
    - name: ISTIO_META_APP_CONTAINERS
      value: nginx
    - name: ISTIO_META_CLUSTER_ID
      value: Kubernetes
    - name: ISTIO_META_INTERCEPTION_MODE
      value: REDIRECT
    - name: ISTIO_META_WORKLOAD_NAME
      value: pod1
    - name: ISTIO_META_OWNER
      value: kubernetes://apis/v1/namespaces/default/pods/pod1
    - name: ISTIO_META_MESH_ID
      value: cluster.local
    - name: TRUST_DOMAIN
      value: cluster.local
    image: docker.io/istio/proxyv2:1.10.4
    name: istio-proxy
    ports:
    - containerPort: 15090
      name: http-envoy-prom
      protocol: TCP
    readinessProbe:
      failureThreshold: 30
      httpGet:
        path: /healthz/ready
        port: 15021
      initialDelaySeconds: 1
      periodSeconds: 2
      timeoutSeconds: 3
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      privileged: false
      readOnlyRootFilesystem: true
      runAsGroup: 1337
      runAsNonRoot: true
      runAsUser: 1337
    volumeMounts:
    - mountPath: /var/run/secrets/istio
      name: istiod-ca-cert
    - mountPath: /var/lib/istio/data
      name: istio-data
    - mountPath: /etc/istio/proxy
      name: istio-envoy
    - mountPath: /var/run/secrets/tokens
      name: istio-token
    - mountPath: /etc/istio/pod
      name: istio-podinfo
  initContainers:
  - args:
    - istio-iptables
    - -p
    - "15001"
    - -z
    - "15006"
    - -u
    - "1337"
    - -m
    - REDIRECT
    - -i
    - '*'
    - -x
    - ""
    - -b
    - '*'
    - -d
    - 15090,15021,15020
    image: docker.io/istio/proxyv2:1.10.4
    name: istio-init
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
        drop:
        - ALL
      privileged: false
      readOnlyRootFilesystem: false
      runAsGroup: 0
      runAsNonRoot: false
      runAsUser: 0
  volumes:
  - emptyDir:
      medium: Memory
    name: istio-envoy
  - emptyDir: {}
    name: istio-data
  - downwardAPI:
      items:
      - fieldRef:
          fieldPath: metadata.labels
        path: labels
      - fieldRef:
          fieldPath: metadata.annotations
        path: annotations
      - path: cpu-limit
        resourceFieldRef:
          containerName: istio-proxy
          divisor: 1m
          resource: limits.cpu
      - path: cpu-request
        resourceFieldRef:
          containerName: istio-proxy
          divisor: 1m
          resource: requests.cpu
    name: istio-podinfo
  - name: istio-token
    projected:
      sources:
      - serviceAccountToken:
          audience: istio-ca
          expirationSeconds: 43200
          path: istio-token
  - configMap:
      name: istio-ca-root-cert
    name: istiod-ca-cert
status: {}
---

istio의 sidecar가 nginx pod에 삽입되게 된다.

      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi

사용하는 자원의 제한은 위와같다. istio-init(initcontainer) proxy(envoy) 가 추가된다.

kubectl label namespace default istio-injection=enabled
namespace/default labeled
kubectl get ns -L istio-injection
NAME              STATUS   AGE   ISTIO-INJECTION
default           Active   46m   enabled

namespace 에 라벨을 붙이면 자동으로 그뒤론 NS 에 sidecar가 붙게된다.

k run nginx-istio --image=nginx --restart=Never
pod/nginx-istio created
k get pod
NAME          READY   STATUS            RESTARTS   AGE
nginx-istio   0/2     PodInitializing   0          4s
pod1          2/2     Running           0          5m11s

이제 sidecar를 본격적으로 확인해보자.

kubectl apply -f istio-1.10.4/samples/addons

아까 다운로드한 istio 에서 샘플로제공된 애드온을 설치한다. 위와같은 명령어를 치면 모든 애드온이 설치된다. 애드온내부에 있는 특정 애드온만도 설치가능하니 필요하면 특정 애드온만 설치해도 된다.

kiali.yaml 를 설치할때 kind 에 MonitoringDashboard 가 있어야 설치가 되는데 처음에 한꺼번에 다 배포를 하면 실패한다 그럼 그냥 쿨하게 명령어 한번더 입력해주자.

이제 애드온으로 접근하기위해선 애드온의 서비스를 퍼블릭하게 변경해줘야하는데, 나는 이전에는 yaml를 손수 수정했는데 이부분이 싱크빅하다.

k get svc -n istio-system grafana -o yaml | sed -e "s/type: ClusterIP/type: LoadBalancer/" | kubectl apply -f -
service/grafana configured
k get svc -n istio-system kiali -o yaml | sed -e "s/type: ClusterIP/type: LoadBalancer/" | kubectl apply -f -
service/kiali configured
k get svc -n istio-system tracing -o yaml | sed -e "s/type: ClusterIP/type: LoadBalancer/" | kubectl apply -f -
service/tracing configured

sed 로 수정해서 바로 적용한다. 와우..당연히 내가 못하는건 아닌데 관념의 차이로 인하여 이런 사용을 생각못했다. 다음엔 써먹어야지

ubectl get svc -n istio-system
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP                                                                    PORT(S)                                                AGE
grafana                LoadBalancer   172.20.162.75   a6d32baedc66b4633bb7fbb0875c6132-465014933.ap-northeast-2.elb.amazonaws.com    3000:30572/TCP                                                3m51s
istio-egressgateway    ClusterIP      172.20.129.21   <none>                                                                         80/TCP,443/TCP                                                21m
istio-ingressgateway   LoadBalancer   172.20.95.93    a0e6177dd9cb64884bd2893028c04328-781274984.ap-northeast-2.elb.amazonaws.com    15021:31227/TCP,80:30590/TCP,443:32395/TCP,31400:32264/TCP,15443:32750/TCP   21m
istiod                 ClusterIP      172.20.90.49    <none>                                                                         15010/TCP,15012/TCP,443/TCP,15014/TCP                                        21m
jaeger-collector       ClusterIP      172.20.99.248   <none>                                                                         14268/TCP,14250/TCP                                                3m51s
kiali                  LoadBalancer   172.20.96.205   a313dbdb158064d578d88c0a022bc845-1007771282.ap-northeast-2.elb.amazonaws.com   20001:30296/TCP,9090:30713/TCP                                               3m51s
prometheus             ClusterIP      172.20.50.6     <none>                                                                         9090/TCP                                                3m50s
tracing                LoadBalancer   172.20.58.118   a9da5b64099ed4fd3b5abdf3b1cd9ebe-68617878.ap-northeast-2.elb.amazonaws.com     80:30295/TCP                                                3m51s
zipkin                 ClusterIP      172.20.76.230   <none>                                                                         9411/TCP                                                3m51s

샘플 manifest 중에 bookinfo 가 있다.

샘플에서 보여주는것은 트래픽이 어떻게 흐르는지 시각화로 보여주는것이다.

문제가 생길경우 다음과같이 UI 와 로깅으로 확인이 가능하다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50

위의 에러는 기본적인 destination rule 을 설정하지 않은 상태로 review 에 대한 룰을 설정해서 그렇다.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productpage
spec:
  host: productpage
  subsets:
  - name: v1
    labels:
      version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ratings
spec:
  host: ratings
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v2-mysql
    labels:
      version: v2-mysql
  - name: v2-mysql-vm
    labels:
      version: v2-mysql-vm
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: details
spec:
  host: details
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---

destination rule 을 설정하고 보면 reviews rule 이 정상적으로 작동하는것을 알수있다.

적용전
적용후

가중치에 의하여 v2/v3로만 라우팅 되는것을 확인할수 있다.

istio는 조만간 블로그에 적용후에 더 자세히 다뤄보도록 하겠다.

좋은 주말되시라!