반응형

들어가는 글

Istio를 설치할 때, 다양한 설치 방법이 있다. 그래서 Istio를 처음 접할 때, 다양할 설치 방법 때문에 무엇부터 시작해야 할지 망설이게 된다. 이런 고민을 조금이라도 덜기 위해 각 설치 방법의 장점과 단점을 알아보고자 한다.

 

우선, 가장 흔하게 사용하는 Istio 설치 방법은 아래의 4가지가 있다.

  • istioctl install     <-- 내가 생각하는 Best Choice
  • istio operator
  • istioctl manifest generate
  • helm chart

각 설치 방법의 특징과 장점 및 단점은 아래와 같다.

 

 

istioctl install

`istioctl` 명령 도구를 사용하여 istio를 설치하는 것이 가장 보편적인 설치 방법이다. 그리고 'istio dev community`에서 이 설치 방법을 권장하고 있다.

Pros:

  • `istioctl` 명령 도구가 설정 오류에 대한 확인을 해준다.
  • `istioctl` 명령 도구가 'IstioOperator' API를 사용한다.
  • 'In-cluster privileged pods'가 필요하지 않다. `istioctl` 명령 도구를 이용해서 설정 변경이 필요할 때마다 설정을 적용해준다.

Cons:

  • 다른 설치 방식에 비해서 `istioctl` 명령 도구 프로그램의 버전을 실제 istio의 버전과 맞추어줘야 하는 일이 필요하다. 

 

istio operator

Pros:

  • `istioctl` 같은 별도의 명령 도구 프로그램이 없이, kubernetes의 Operator 패턴을 이용하면 된다.

Cons:

  • 'Istio Operator'가 istio가 설치되는 kubernetes cluster 내부에 있어야 하고, 상당히 높은 cluster management 권한을 가지게 되므로, 자칫하면 보안(security)가 허술해지는 실수를 범할 수 있다.

 

 

istioctl manifest generate

나처럼 Istio 자체를 분석하려는 사람이 쓰는 방법이지 않을까 싶다. Kubernetes와 Istio를 많이 아는 사람이 아니라면, 이 방법은 복잡하게 느껴질 수 있을 것이다. Kubernetes와 Istio를 파헤치고 배우는 학생이라면 한번쯤 시도해볼만한 설치 방법이다. (나의 개인적인 느낌으로 하는 말이다 ^^)

어짜피 istioctl이나 istio operator도 원본 Application의 Pod manifest를 hooking하여 istio에 필요한 설정 항목을 Patch하는 것이기 때문에, Istio 및 app이 구동하는 과정을 동일한 흐름일 것이다.

Pros:

  • `istioctl`이 생성한 chart를 사람이 직접 열람할 수 있다.

Cons:

  • chart, manifest를 직접 이용하는 방식이기 때문에 `istioctl`의 설정 검증 같은 절차가 없다.
  • 초보자가 사용하기에 절차가 복잡하다.
  • Error reporting이 허술하다.

 

 

Helm chart

개인적인 생각에 helm chart에 익숙한 사용자라면 써볼만한 설치 방식이지만, 설정 validation이 허술해서 권장할 만한 설치 방법은 아닌 듯 하다.

 

 

 

결론


개발자가 Istio를 스터디하고, 분석해야 하는 상황이 아니라면 `istioctl` 명령 도구를 이용하여 istio를 설치하고 관리하는 것이 좋다.
아래 Web Docs를 따라하는 것이 Best Choice 라고 생각한다.

https://istio.io/latest/docs/setup/install/istioctl/

 

Install with Istioctl

Install and customize any Istio configuration profile for in-depth evaluation or production use.

istio.io

 

위 Web Docs가 너무 길어서 다 읽고, 따라하기 귀찮다면, 아래 2개의 명령만 수행해보길~~~

## Istio Controller 설치 및 Ingress, Egress Gateway까지 한번에 설치하려면, 아래 명령을 수행
$ istioctl install --set profile=demo

## Test가 끝나고,  Istio 관련 모든 Kubernetes Resource를 삭제하려면, 아래 명령을 수행
$ istioctl x uninstall --purge

 

 


만약, Istio를 포함해서 Example App이 실제로 돌아가는 것까지 테스트하고 싶다면 아래 Web Docs를 따라하는 것이 좋다.

 

https://istio.io/latest/docs/setup/getting-started/

 

Getting Started

Try Istio’s features quickly and easily.

istio.io

 

반응형

 

작성일: 2024년 2월 3일

 

 

생일, 결혼기념일, 송년회 같은 특별한 날에는 와인 샵에 가서 와인을 구입하곤 하는데, 수백 종류의 와인 중에서 무엇을 골라야 할지 막막할 때 많다. 이럴 때 와인 선택하기에 도움이 될만한 내용을 이 페이지에 적어볼까 한다.

 

 

 

포도 품종

 

와인을 만들기 위해 사용되는 포도 품종이 200 여 가지가 된다. 그리고 그 중에서 대중적으로 사용되는 품종은 10 여 종이 된다.

주의: 
포도 품종에 따라 독특한 맛과 향기가 있지만 실제로 상품성이 높은 와인을 만들 때 두 가지 품종을 섞어서 와인을 만들기 때문에 꼭 아래 적은 향기와 맛이 나는 것이 아니다. 
그러니까 품종이나 재배 지역은 참고만 하는 것이 좋다.

 

Chardonnay  샤르도네

  • 꽃향, 과일, 버터향이 강하다.
  • 가장 인기가 많다.
  • 화이트 와인, 샴페인 생산에 사용한다.
  • 주요 재배 지역
    • France:   Bourgogne 부르고뉴 ,  Champagne 샹파뉴 ,  Jura 쥐라 ,  Languedoc 랑그도크 ,  Provence 프로방스
    • US:  Califonia
    • Canada
    • 칠레
    • Argentina
    • South Africa
    • China,
    • Australia

Sauvignon  소비뇽

  • 허브향
  • 화이트 와인 생산에 사용한다.
  • 주요 재배 지역
    • France:  Centre-Val de Loire 상트르발 드 루아르 ,  Bordeaux 보르도
    • Spain
    • 뉴질랜드
    • US:  Califonia
    • 칠레
    • South Africa

Chenin  슈냉

  • 부드럽기 때문에 스파클링 와인, 드라이 와인 등에 사용한다.
  • 주요 재배 지역
    • France:  Loire 루아르
    • US:  Califonia
    • South Africa

Gewurztraminer  게뷔르츠트라미너

  • 장미 향기
  • 독일어 Gewurz (게뷔르츠) 뜻이 "향신료이다.
  • 주요 재배 지역
    • France:  Alsace 알자스
    • 독일
    • Austria
    • Italy

Viognier 비오니에

  • 살구 , 복숭아 향기
  • 무겁고 텁텁한 맛
  • 프랑스 Rhone 론 지역의 최고급 와인 와인너리에서 만들기 때문에 비싸다.
  • 주요 재배 지역
    • France:  Rhone 론 ,  Languedoc 랑그도크
    • US:  Califonia
    • Australia

Semillon 세미용

  • Botrytis Cinerea 균(포도에 당분을 축적시켜 단맛이 나는 와인을 만드는 데 사용)에 감염된 것을 Noble rot ( 귀부병 )이라고 한다.
  • 인기가 높다.
  • 가격이 많이 높다.
  • 주요 재배 지역
    • France:  Bordeaux 보르도
    • Australia
    • US
    • South Africa

Riesling 리슬링

  • 테루아 (토질)의 영향을 많이 받는다.
  • 광물 향기
  • 귀부 포도 상태로 아이스 와인을 생산한다.
  • 화이트 와인
  • 주요 재배 지역
    • France:  Alsace 알자스
    • 독일
    • 룩셈부르크
    • Australia,
    • 뉴질랜드
    • Canada

Marsanne 마르산

  • 아몬드 향기
  • 주요 재배 지역
    • France: Rhone ,  Languedoc
    • Australia
    • US

Rolle-Vermentino 롤-베르멘티노

  •  배 향기
  • 쓴 맛이 난다.
  • 주요 재배 지역
    • France:  Languedoc-Roussillon
    • Italy

Muscat

  • 그리스가 원산지
  • 단맛이 강해서 젊은 사람일수록 싫어하는 와인
  • 주요 재배 지역
    • France:  Alsace
    • Italy
    • 그리스
    • Spain
    • 포르투갈

Melon de Bourgogne ( Muscadet ) 믈롱 드 부르고뉴 ( 뮈스카데 )

  • 레몬 향기
  • 바닷물 짠맛이 난다. 그래서 해산물과 어울린다.

Pinot Gris 피노 그리

  • 이 품종으로 색이 매우 연한 로제 와인을 만든다.
  • 레몬 향기 + 향신료 냄새

Pinot Noir 피노 누아

  • 와인으로 만들면 루비 색깔이다.
  • 동물 가죽 냄새가 난다.

Cabernet-Sauvignon 카베르네 소비뇽

  • 이 품종으로 만든 와인은 대중적이다.
  • 담배 ,  들짐승고기 ,  삼나무 냄새가 난다.

Cabernet Franc 카베르네 프랑

  • Cabernet-Sauvignon 품종의 선조 품종이다.
  • 파프리카 향기

Merlot 메를로

  • 과일 향기가 풍부하다.

Syrah 시라

  • 후추 향기 ,  감초 향기

Grenache 그루나슈

  • 자두 , 초콜릿 , 풀 향기
  • 초콜릿과 같이 마시면 좋다.
  • 주요 재배지
    • France:  Rousillon 루시용

Gamey 가메

  • 프랑스 Beaujolais 보졸레 지역의 대표 품종
  • 타닌이 적어서 신선한 맛이다.
  • 바나나 , 사탕 향기
  • 주요 재배지
    • France:  Beaujolais 보졸레 ,  Pays de Loire 페이 드 루아르 ,  Ardeche 아르데슈 ,  Brougonge 부르고뉴

Mourvedre 무르베드르

  • 이 품종으로 알코올 도수가 높은 와인을 생산한다.

Malbec 말베크

  • Argentina 와인의 주력 품종
  • Ameria 대륙에서 인기가 많다.

Carignan 카리냥

  • 대량 생산용 품종
  • 자갈 냄새

Sangiovese 산지오베제

  • 이탈리아 품종
  • 허브향

Nebbiolo 네비올로

  • 이탈리아에서 가장 명성이 높다.
  • 재배가 어렵고, 생산량이 적어서 많이 비싸다.  (일반인이 먹을 수 있는 가격이 아니다)
  • 주요 재배지
    • Italy:  피에몬테,  롬바르디아

 

 

 

포도 재배 지역

상식 용어: 떼루아

와인의 특성을 결정하는 "기후, 토양" 같은 환경을 의미한다.

포도 나무는

  - 섭씨 10도에서 성장을 시작하고,

  - 섭씨 17~20도에서 개화하고

  - 섭씨 20도가 넘어가면, 쑥쑥 큰다.

그리고 좋은 포도밭은 산기슭이면서 남향을 향한다. (포도뿐 아니라 대부분 작물이 이런 땅에서 잘 자란다)

 

프랑스 와인 생산지 (출처: Wine Folly)

 

Bordeaux (보르도)

Gironde(지롱드 강) 주변Medoc(메독) 지역이 있고, 그 안에 Pauillac(포이약), Margaux(마고), Saint-Estephe(생테스테프), Saint-Emilion(생테밀리옹), Pomerol(포므롤) 등 와이너리 마을이 있다. 

보르도 지방에서 포도밭을 소유하며 와인을 생산하고 판매하는 와이너리를 Chateau(샤토, 샤또)라고 부른다.

 

Wine Map of Bordeaux (from Wine Folly)

 

 

Bourgogne (부르고뉴)

이 지역은 여러 품종을 블렌딩하지 않고, 단일 품종으로 와인을 만든다.

(블렌딩하는 와이너리도 있다. 어디서든 예외라는 것은 있으니까 ^^)

재배하기 까다롭다는 피노 누아 품종이 잘 자라는 지역.

이 지역에서는 와이너리를 Domaine(도멘)이라고 부른다. 보르도 지역의 샤또와 같은 개념이다.

보르도 처럼 와인 등급 체계가 별도로 있다.

 

 

Rhone (론)

로마 가톨릭 교황들이 즐겨 마신 것으로 유명하다.

론강을 주변에 위치.

보르도 처럼 와인 등급 체계가 별도로 있다.

 

Alsace (알자스)

독일과 접한 지역.

 

Champagne (샹파뉴)

샴페인의 본고장.

샤르도네, 피노 누나, 피노 뫼니에 품종을 중심으로 기포를 가진 샴페인을 생산.

 

Languedoc Roussillon (랑그독 루시용)

프랑스에서 가장 오래된 와인 생산지

가장 많은 양의 와인을 생산하는 곳.

AOC(P) 등급에 연연하지 않고 와이너리마다 개성을 담은 창의적인 와인을 만든다.

무르베드로, 시라, 그르나슈, 카리냥 품종을 사용한 와인을 생산.

 

Provence (프로방스)

로제 와인이 대표 상품.

 

 

추천 블로그: 프랑스 와인에 대한 자세한 설명이 있는 블로그이다 (제목: 와인의 교과서, 프랑스)

  -  https://brunch.co.kr/@lifedesigneer/168

 

 

Vintage 빈티지  (포도를 수확한 해)

Vintage 빈티지는 포도가 수확되고 와인이 양조된 해를 가리킨다.

(프랑스어 Vendange 방당쥬에서 유래)

예를 들어, 와인 병에 2023라고 적혀 있으면 2023년에 수확한 포도로 만든 와인이다.

일반적으로 날씨가 좋아야 와인을 만들기 좋은 포도를 얻을 수 있다. (하늘이 맑고 햇살이 좋았다면 포도가 달달하게 잘 익을 것이다)

와인을 만들기에 좋은 포도가 뭐지? 

당도(단맛의 정도)가 높은 포도이다.  단맛이 약한 포도는 와인이 만들어지지 않는다.

 

어떤 Vintage 빈티지가 좋은가?

프랑스 와인이라면,

2005년, 2009년,  2015년 빈티지가 좋다.

대부분 와인 생산지는 1년 내내 날씨가 좋고, 수십년간 평균적으로 봐도 날씨가 계속 좋은 곳이기 때문에 Vintage에 따라 와인의 품질이 들쑥날쑥 변하지 않는다.

그리고 조금 날씨가 안 좋은 해가 있다고 하더라도 와인 제조 기술이 높아서, 포도의 품질이 떨어진 것을 "와인 제조 기술"로써 보정할 수 있다. 와인 제조 업자, 유통 업자가 아니라면 Vintage에 따른 품질 차이를 느끼지 못할 것이다.

 

 

Vintage Chart 에 대한 부정적 생각

뭐든 점수를 메겨야 하는 인간의 욕구가 술 / 와인에도 그대로 적용된다.

Vintage Chart에 명확하게 드러난 좋은 와인과 나쁜 와인...

그런데 우리가 E마트, 롯데마트에서 구입하는 5만원 이하의 와인이 빈티지에 영향을 받는 와인인가 생각해보면, 그건 아니다.

수십만원 수백만원하는 고급 와인이라면, 그리고 아주 소중한 사람에게 선물하는 와인이라면, 꼼꼼하게 따져봐야 하니까 Vintage Chart를 보면서 와인을 고르는 것이 나쁠리는 없다.

그런데 말이다... 대형마트에서 파는 5만원 이하의 와인에 이런 Chart가 필요할까 싶다.

그리고 블라인드 테스트를 해보면, Vintage를 구별할 사람이 없다.

 

 

AOC, AOP, AOC(P) - 프랑스 와인 등급 체계

프랑스 정부가 와인 생산 과정과 와인의 품질을 관리하기 위해 만든 체계이다.

그러나 실제로 창의적이고 아주 고급진 와인을 만드는 샤또(또는 제조사)는 이런 정부의 관리 체계를 따르지 않는다.

그래서 사실상 고급 와인인데 AOC(P) 등급이 바닥인 경우가 있다.

소비자 입장에서는 참고만 하고, 너무 이 등급 체계를 따를 필요는 없다.

 

이 등급 체계와 별개로 Bordeaux(보르도) 지역에서는 와인 생산자가 만든 등급 체계가 있다.

(최고 등급에 해당하는 명칭만 열거해보겠다. 와인 병에 아래와 같은 레이블이 있는지 찾아보는 것도 재미있을 듯 ^^)

  - Bordeaux Grand Cru Classe

  - Saint-Emilion Grand Cru Classe

  - Grave Grand Cru Classe

  - Cru Bourgeois(부르주아)

 

 

 

 

Champagne 샹파뉴 , 샴페인

 

스파클링 와인 중에서 프랑스 Champagne 상퍄뉴 지역에서 만든 술이다.

샴페인은 영어로 읽을 때 발음이고,  원래 프랑스어로 읽을 때는 샹파뉴 이다.

샹파뉴 지역이 아닌 다른 지역에서 만든 스파클리 와인은 크레망, 뱅 무소 라고 부른다.

(참고로, 샹파뉴이든 크레망이든 뱅 무소이든 제조법은 동일하다.  재배지와 생산지만 다를 뿐이다)

 

 

 

Chateau 샤또

와인 가게에 진열된 수만은 와인병을 보면 와인병에 Chateau 샤또 라는 표기를 자주 보게 된다. 

예를 들면, 샤또 마고 Chateau Margaux, 샤또 오브리옹 Chateau Haut-Brion, 샤또 무통 로실드 Chateau Mouton Rothschild, 샤또 라뚜르 Chateau Latour 같은 라벨이다.

샤또가 무엇일까?

사전적 의미만 보면, 각 지역에 있는 뾰족한 지붕의 성(Castle)이다.

그러나 와인 분야에서는 샤또가 의미가 드라다.

와인 분야에서 샤또포도나무를 재배하는 밭, 와인 만드는 장소, 와인 저장실 등을 포함한다.

즉, 영어로 와이너리, 우리나라 말로 과수원 + 양조장 이런 느낌일 것이다.

왜냐하면 옛날에는 포도원을 소유한 귀족이 자신이 소유한 성(Chateau)에서 포도를 재배해 와인을 만들고 이 와인에 성(Chateau, Castle) 이름을 붙였기 때문이다.  옛날에는 그랬고, 요즘은 기업화된 양조장 쯤으로 생각하면 될듯.

그런데 France 모든 지역에서 Chateau 라는 이름을 사용했던 것은 아니다. 보드로 지역에서만 Chateau 표기를 사용했다.

이것도 요즘에는 France 밖 다른 나라에서 와인 브렌드에 Chateau를 붙이면서 Chateau가 고급 와인이라는 인식이 희석되었다.

 

참고로, 보르도 지방에 있는 Chateau만 해도 9,000개가 넘고, 이 Chateau를 좋은 Chateau와 나쁜 Chateau를 구분해야 했다. 그래서 등급제를 도입했는데, 그  중에서 1등급 Chateau는 아래와 같다.

  • Chateau Lafite-Rothschild
  • Chateau Margaux
  • Chateau Latour
  • Chateau Haut-Brion Pessac
  • Chateau Mouton-Rothschild

 

 

 

 

 

와인 병에 적힌 라벨 읽는 방법

# TODO :  와인 라벨에 관한 내용은 나중에 작성해야겠다.

 

 

 

마셔본 와인(Wine) 중에서 괜찮았던 와인

Slam Dunk Red Wine (슬램덩크 레드 와인)

  • 가격: 2만원 후반 (대략 27,000 ~ 28,000원)
  • 제조사: Napa Wine Company LLC, California, USA
  • 포도 품종: 쁘띠 시라 55%, 진판델 45%  (나는 이 독특한 맛이 좋았다)
  • 당도: Dry
  • 향:
    • 제비꽃, 블랙베리 파이, 달콤한 블랙 체리와 다크 초컬릿의 풍미가 강하다.
    • 라즈베리, 토스트 바닐라 풍미가 길게 남는다.
  • 같이 먹으면 좋은 음식 (안주): 치즈, 하몽, 육포
  • 도수: 14.8  (알코올 도수가 조금 더 높은데, 꽤 일찍 취했다 ^^. 그런데 머리는 전혀 아프지 않아서 좋았다)
  • 내가 구입해서 먹은 날: 2022년 12월 31일
  • 리뷰, 제품 판매 사이트:
  • 총평:
    • 향긋하고, 단맛도 있어서 아직 고등학생이 있는 우리 집에서는 딱 좋다. (식사할 때 아이들은 50ml 정도 같이 마신다.)
    • 술 특유의 쓴맛을 싫어하는 사람은 이 와인을 괜찮은 선택일 것 같다.
    • 이 와인을 3잔을 마셨는데, 다음 날 몸이 너무 개운했다. (이점이 제일 좋았다. 꼭 마취 주사를 맞고 잠잔 것 같은 느낌.)
    • 다음 가족 파티할 때 또 구입해서 마실 생각이다.

 

My Pet Tempranillo (마이 펫 템프라니요)

  • 가격: 26,000원
  • 제조사: Bodegas Alceno S.A, Spain
  • 포도 품종: Tempranillo (템프라니요)
  • 당도: 중간
  • 타닌: 중간
  • 산미: 중간
  • 향: 무화과, 체리, 삼나무, 딜, 담배
  • 도수: 13%
  • 참고 사이트: 
    • https://www.letswine.co.kr/product/detail.html?product_no=556
  • 총평:
    • 어떤 음식이든, 어떤 분위기든 다 잘 어울리는 와인이다.
    • 블랙베리와 딸리, 체리향이 가득하고 시가(담배) 냄새가 약간 난다.
    • 여러 맛이 잘 조화를 이룬다.

 

 

반응형

 

잠깐 !!!
만약, 단순히 Container, Pod 내부에서 Root 권한 또는 Host OS 자원에 대한 접근 권한이 필요한 경우라면
이 블로그를 읽고 따라하기 보다는 아래 블로그를 읽고 간단하게 테스트하기를 권장한다.

https://andrewpage.tistory.com/191

 

 


 

 

Pod 내부의 Application이 Host OS의 Root User 권한으로 OS 자원에 접근하거나 명령을 수행해야 한다면, 해당 'namespace'에

privileged 속성 또는 privilieged와 동등한 수준의 자체 정의한 SecurityContextConstraints(SCC)를 추가해야 한다.

 

SCC 생성

나만의 SCC를 생성해보자.

$  cat << EOF > my-scc.yaml

kind: SecurityContextConstraints
metadata:
  name: andrew-scc
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegeEscalation: true
allowPrivilegedContainer: false
allowedCapabilities:
- NET_ADMIN
- NET_RAW
- NET_BIND_SERVICE
apiVersion: security.openshift.io/v1
defaultAddCapabilities: null
fsGroup:
  type: RunAsAny
groups:
- system:cluster-admins
priority: 10
readOnlyRootFilesystem: false
requiredDropCapabilities:
- MKNOD
runAsUser:
  type: RunAsAny
seLinuxContext:
  type: MustRunAs
supplementalGroups:
  type: RunAsAny
users: null
volumes:
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- projected
- secret

EOF

 

위와 같이 my-scc.yaml을 작성했다면, 이 파일을 OCP에 적용한다.

## 참고로, scc는 namespace마다 있는 것이 아니다. 
## 따라서 namespace를 지정하지 않고, 아래 명령처럼 scc를 생성한다.

$  oc apply -f my-scc.yaml

 

이렇게 생성한 SCC를 내가 사용할 ServiceAccount와 binding한다.

$ oc create ns andrew-project
$ oc adm policy add-scc-to-group andrew-scc system:serviceaccounts:andrew
$ oc adm policy add-scc-to-user andrew-scc  -z andrew  -n andrew-project

# SCC 정보를 확인하는 명령
$ oc describe scc andrew-scc

# 'andrew' ServiceAccount로부터 'andrew-scc' SCC를 삭제하는 명령
$ oc adm policy remove-scc-from-user andrew-scc  -z andrew -n andrew-project

 

 

추가로 Pod Deploy할 때, 아래와 같이 'securityContext' 항목을 설정해야 한다.

 

# File name: my-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ubuntu-pv
  labels:
    app: ubuntu-pv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ubuntu-pv
  template:
    metadata:
      labels:
        app: ubuntu-pv
    spec:
    ## NOTE: 이 부분을 추가 !!!
      securityContext:
        runAsUser: 0
      containers:
      - name: ubuntu-pv
        image: myharbor.andrew.space:8080/my-ubuntu:0.1.2
        ## NOTE: 이 부분을 추가 !!!
        securityContext:
          capabilities:
            add:
              - "NET_ADMIN"
              - "NET_RAW"
              - "NET_BIND_SERVICE"

 

 


 

 

여기까지는 그냥 SecurityContextConstraints에 관한 이해없이 따라해도 잘 동작한다.

그런데 만약 SecurityContextConstraints에 대해서 깊이 있는 지식을 얻고 싶다면, 아래의 Red Hat Blog를 읽어볼 것을 추천한다.

SecurityContextConstraints 방식으로 Process의 실행 권한을 제어하는 방법 외에도 Linux에서 전통적으로 사용하는 Stick Bit(SETUID)와 File Capability 방식으로 Binary File을 만들고, Container Image를 미리 제작하는 방법도 같이 소개하고 있다.

어떤 방식이 더 편하고, 보안(Security)이 우수한지는 사용하는 사람이 판단할 일이다.

 

 

 

추천 Blog - Capabilities in OpenShift (OCP)

 

https://cloud.redhat.com/blog/linux-capabilities-in-openshift

 

Linux Capabilities in OpenShift

We know that Linux has two types of users: Privileged and Unprivileged.

content.cloud.redhat.com

 

 

추천 Web Docs

아래 Web Docs에서 Chapter 15.에 가장 확실한 설명이 있다.

https://access.redhat.com/documentation/ko-kr/openshift_container_platform/4.10/html-single/authentication_and_authorization/index

 

인증 및 권한 부여 OpenShift Container Platform 4.10 | Red Hat Customer Portal

이 문서에서는 OpenShift Container Platform에서 ID 공급자를 정의하는 방법을 설명합니다. 또한 클러스터를 보호하기 위해 역할 기반 액세스 제어를 구성하는 방법도 알아봅니다.

access.redhat.com

 

 

 

반응형

공황장애(Panic)가 심해지면서 정신건강의학과 의원에 다니고 약물 치료를 한 이후로 Panic 증상이 많이 줄었지만, 여전히 공황장애 때문에 못 하는 것이 고속도로에 있는 2km가 넘는 긴 터널을 통과하지 못 한다.

약물 치료 전에는 500m짜리 터널도 못 지나가서 터널 입구에서 차를 세운 적도 있었서 그때보다는 많이 좋다고 생각하지만, 힘들고 두려운 것은 어쩔 수 없다. 이성적으로 제어할 수 있는 영역의 문제가 아니다보니, 그냥 순응하는 수 밖에 없네.

 

그래서 어디 멀리 여행을 갈 때는 목적지까지 중간에 긴 터널이 있는지 확인한다. 경로에 2km 넘는 터널이 있다면, 고속도로를 포기하고 구불구불하고 제한 속도가 있는 국도, 지방도를 이용한다.

같이 동행하는 가족은 1시간 정도 차를 타는 시간이 더 길어져서 힘들겠지만, 나름 국도 주변의 풍경은 고속도로보다는 볼만하다. 산 경치가 터널에 비교할 바가 아니지 않겠는가 ^^  (좋게 생각하자~ 긍정적인 생각이 병을 고치게한다)

 

안양(인덕원) ~ 강원도 양양

긴 터널에 대한 폐소 공포 증상 때문에 터널을 피한다고 생각하는 것보다는 터널을 지날 때 느껴보지 못한 좋은 풍경과 작은 마을에 들러서 느끼는 여유로움 때문에 국도, 지방도를 간다고 생각하면 마음이 편안해진다.

그래서 나는 강원도 양양을 갈 때,  인제군청과 한계령휴게소를 지나는 도로를 이용한다. 

서울 -> 홍천군 -> 인제군 -> 한계령휴게소 -> 양양군(해변)
  * 홍천군: 운전 피로를 풀기에 좋은 국밥집이 있다. 뜨끈한 국밥 한 그릇 먹고 출발하면 기분이 좋아진다.
  * 인제군: 인제군청과 인제 성당에서 멀지 않은 곳에 철판짜장면으로 유명한 식당이 있는데,
                 짜장면의 비쥬얼이 이색적이고, 철판이라서 짜장면에서 불맛을 느낄 수 있다.
  * 한계령휴게소: 경치가 너무 좋아서, 저절로 차를 멈워 세우게 된다. 이 맛에 국도로 운전한다 :)

홍천에서 인제군을 가는 국도에도 터널이 몇개 있기는 하지만, 서울양양고속도로만큼 긴 터널은 아니고 수백 미터짜리 짧은 터널이다. 그래서 폐소공포에 대한 부담없이 운전할 수 있다. 

 

안양(인덕원) ~ 전라남도 여수

서울에서 출발해서 논산까지는 고속도로인데도 불구하고 터널이 없다. 그러나 논산 이남으로 가면, 2km가 넘는 터널이 나온다. 

따라서 서울~논산 구간은 고속도로를 이용하고, 논산~여수 구간은 국도를 이용하면 좋다.

특이한 점은 논산~여수 구간의 국도가 속도 제한이 80km/h이지만, 실제 이 도로를 이용하는 차량의 평균 속도는 100~110km 정도이고 신호등이 거의 없어서 고속도로와 시간 차이가 많이 나지 않는다.

그리고 국도를 이용해서 여수를 가다보면, 중간에 살짝 빠져서 지리산 노고단을 갈 수 있어서 좋다.

 

 

 

반응형

 

 

들어가는 말

이 Git에 관해 글을 처음 쓰기 시작한 날은 2021년 2월 20일이다.

요구사항 경청하고, 요구 사항 분석하고, 구조 설계, 개발(구현), 테스트, 회의, 멤버 관리 등 매일 해야 하는 업무에 시간이 쫓기고

집에 오면 아내와 아이들과도 시간을 보내야 하니까 솔직히 긴 호흡으로 깊은 내용의 블로그를 쓴다는게 쉽지 않다.

그런데 Git 개념을  1~2시간 이내의 글을 쓴다고 될 일은 아니라서, 한달 정도 매일 시간을 조금씩 내면서 써볼까 한다.

( 아마 작성 중간에 글을 읽는 분도 계실텐데, 양해를 구합니다~ )

 

처음부터 Git을 사용한 사람이라면 Git의 Version과 Work Space 관리가 당연하게, 자연스럽게 받아들여질 것이다.

그런데 나처럼 개발을 시작한지 20년이 사람은 비슷한 듯 다른 SVN과 Git의 Version 관리 방식이 헷갈린다.

자꾸 SVN을 사용하던 버릇으로 Git 사용하니까 제대로 Git을 사용하지 못하는 나를 발견했다. 

그래서 SVN을 화끈하게 머릿속에서 지워버리고, 새 마음으로 Git을 받아들이기로 했다.  :)

 

 

SVN 그리고 Git 이들은 뭐가 다를까?

대략적으로 SVN과 Git을 비교해보면 이렇다. (개인적인 느낌, 생각이 많이 들어 갔으니까 그냥 참고용으로 봐주세요)

 

비교표 Git SVN (SubVersion)
전반적인 느낌 어렵다.
개념 설명이 잘 된 책을 한번 쭉 읽어야 Git을 Git답게 쓸 수 있다.
개념이 쉽고, 명령어 사용법도 쉽다.

Feature 없는게 없다.
Version 관리의 끝판왕!!!
딱 필요한 핵심 기능을 제공한다.

Branch 관리 Branch, Tag 관리가 편리하다. Bad T.T
코드 분산 관리 OK No
Code Collision(충돌) 조금 관리에 신경쓰면 그럭저럭 충돌을 피할 수 있다. Poor T.T
Multi User 동시 작업 OK 불편하다.
복구 특정 Commit 시점으로 복구하기 편함 Poor

 

그리고 위 표에 언급한 것 말고도, Git은 Github 또는 Bitbucket, GitLab 처럼 Cloud 환경을 제공해주니까 내가 별도로 SVN 서버를 구축하지 않아도 된다.  그냥 내 PC에서 코드 작성하고 GitHub 또는 Bitbucket, GitLab Cloud에 Push하면 되니까 아주 편하다.

 

또 하나, Git이 어려운 이유는 아마도 여러 사람이 같은 Code를 수정하고, 동일한 Repository에 Push를 하면서 어려움을 겪는 것 같다. (내 경우는 특히 그랬다.) 

혼자 Git과 GitHub를 사용할 때는 별 문제 없이 잘 사용했는데 여러 명이 같이 코드를 수정하고 Push하고 Merge를 하려니까 자꾸 불편한 상황이 생겼다.

Git 스터디해보니, 모르고 써서 생기는 불편함이었다. Git 개념과 사용법을 잘 익히고 사용했다면 분명 문제가 없었을 것이다.

 

 

GitHub, GitLab, BitBucket 이들은 무엇인가?

처음에 Git를 접할 때는 GitHub만 보였는데, 실무에서 Git을 많이 사용하다보니 GitLab도 보이고, BitBucket도 보였다.

이들은 비슷하면서 다른데, 아래 표로 정리해봤다.

 

  GitHub GitLab Bitbucket
서비스 제공 회사 Microsoft GitLab Inc. Atlassian
Feature 우리가 OpenSource를 다운로드할 때 접할 수 있는 바로 그 곳 GitHub랑 Feature의 차이를 잘 모르겠다. (내 생각임) Jira 연동이 되서 좋다. (내 생각임)
Web UI 3개 모두 비슷하다. Repository 자체에 대한 관리 UI를 제외하면 거의 같다.
CLI (Command) Git command는 3개 모두 똑같다.  (CLI가 제품마다 다르면 큰일나지 않을까? ^^)
Price Free
(Private Repository는 유료)
Free
(Private Repository는 유료)
Free
(Private Repository는 유료)

 

결국, 3개 모두 기능(Feature)는 비슷하고 가격도 경쟁이 붙어서 그런지 가격도 비슷해졌다.

나는 회사에서 Bitbucket을 구입해서 사용하고 있는데, 확실히 회사의 Project 관리 시스템(Jira, Confluence 등)과 연동되니까 관리하는 입장에서는 Bitbucket이 SW 품질 관리에서 유리한 면이 있다. 즉, 회사에서 사용할 거라면 위 3개 중에서 Bitbucket이 좋다는 뜻 :)

 

그렇다면, 개인적으로 사용할 거라면?

그래도 Bitbucket Cloud 서비스를 이용하는 것이 다른 2가지 제품보다 좋은 것 같다 (개인 의견임)

해외의 대형 Open Source Project에 좀 참여해서 일을 해보니, Atlassian 제품을 이용해서 Open Source Project를 관리하는 Community가 꽤 많고, 나에게 그런 경험이 있어서 그런지 Atlassian의 Bitbucket이 좀더 익숙한 느낌이다.

 

 

Git 설치 (Installation)

 

##
## Mac OS 컴퓨터에 설치하는 경우
##

$  brew install git

$  git --version
git version 2.32.0 (Apple Git-132)

$  git config --global user.name "Peter"

$  git config --global user.email "peter@example.com"

 

 

Git 개념, 동작 방식

나처럼 Version 관리 도구로써 SVN을 먼저 접한 사람은 Git의 동작 방식이 쉽게 이해되지 않는다.

그래도 찬찬히 살펴보면, 알게 되리라 :)

 

Repository가 Local가 Remote로 나누어져있다. 이 부분이 처음 Git을 접하는 사람이 헷갈려하는 부분이다.

Repository를 2개로 나누어서 관리하다보니, Local과 Remote를 명확하게 구분해서 이해하지 않으면 git 명령을 수행할 때마다 헷갈리게 된다.

아래 그림이 쉽게 Local Repository에서 처리되는 내용, Remote Repository에서 처리되는 내용이 잘 구분되서 설명되고 있다.

 

출처&nbsp; https://greenido.files.wordpress.com/2013/07/git-local-remote.png?w=696&amp;h=570

 

출처&nbsp; &nbsp;https://www.devguide.at/en/git/pull-push-the-remote-repository/

 

 

위 그림을 이해했다면, 아래 그림을 이용해서 생각을 더 넓혀보자.

Repository (저장소)는 Remote, Local만 있는게 아니다. Forked Repository라는 것이 있다. 아마 꽤 활성화된(참여자가 많은) Open Source Project는 이 Forked Repository가 꽤 많을 것이다.

 

출처&nbsp;&nbsp;https://www3.ntu.edu.sg/home/ehchua/programming/howto/Git_HowTo.html

 

 

출처&nbsp;&nbsp;https://www3.ntu.edu.sg/home/ehchua/programming/howto/Git_HowTo.html

 

 

출처&nbsp;&nbsp;https://www3.ntu.edu.sg/home/ehchua/programming/howto/Git_HowTo.html

 

 

 

 

TODO : 위 동작 절차(프로세스)에 관해서 상세하게 설명하기  (작성 중)  -->  Coming Soon !!!

 

 

 

 

 

 

 

 

 

Git Branching Model

git-flow

github-flow

 

 

Git Branch 모델(그 중에서도 git-flow)에 관한 제일 유명한 블로그가 있다.

바로 아래 블로그인데, 이 Git Branch 모델에 관해  개발 실무자 입장에서 얘기를 해볼까 한다.

그리고 github-flow 같은 다른 종류의 Branching Model도 다룰까 한다.

 

https://nvie.com/posts/a-successful-git-branching-model/

 

A successful Git branching model

In this post I present a Git branching strategy for developing and releasing software as I’ve used it in many of my projects, and which has turned out to be very successful.

nvie.com

 

 

 

 

읽으면 좋은 Web Docs

https://www.atlassian.com/git/tutorials/learn-git-with-bitbucket-cloud

 

Learn Git with Bitbucket Cloud | Atlassian Git Tutorial

Learn Git with Bitbucket Cloud

www.atlassian.com

 

'Git' 카테고리의 다른 글

Git Ignore (.gitignore) 설정 방법  (0) 2022.07.04
반응형

들어가는 글

App을 개발해서 Container image로 build하여 Kubernetes cluster에 배포하다보면, 어느 순간 비슷하면서 반복적인 YAML 파일을 작성하는 나를 보게된다.

좀더 구체적으로 얘기하자면, HelloWorld라는 App을 구성하는 Pod가 hw-frontend, hw-backend, hw-db 등 3개의 Pod로 구성되어 있다면 Kubernetes cluster에 HelloWorld App을 배포하기 위해서는 이 3개의 Pod를 모두 배포할 수 있는 deployment.yaml을 작성해야 한다.

아마 Kubernetes 운영 경험이 있는 개발자라면 Helm chart로 반복적이거나 뻔한 YAML code를 template 파일로 만들고, 변경되어야 할 부분만 values.yaml로 작성할 것이다.

그런데 이 helm chart도 일정 부분의 반복적이고 루틴한 작업이 계속 만들어지게 된다.

뻔하면서 반복되는 비슷하지만 약간씩 다른 설정 작업을 기계가 대신 해주면 좋겠다는 소망이 생긴다.

(아마 Kubernetes를 1년 정도 사용해서 App을 반복 배포하다보면, 이런 느낌적인 느낌이 생길 듯 ^^)

 

그래서 이런 저런 고민을 해결할 방법을 찾다가 'Mutating Admission Controller + WebHook'이라는 Kubernetes에 내장된 기능을 발견했다.

 

서론이 길어졌다.

이제 본론으로 들어가서, Kubernetes가 제공하는 Admission controller가 무엇이고 일반 개발자가 이 기능을 어떻게 확장할 수 있는지 설명해보겠다.

 

Mutating WebHook 사용 사례 (Use Case)

Admisson controller를 통한 Mutating Webhook 기능을 개발하는 사례는 많이 다양할 것이다.

내가 Mutating Webhook 서버를 개발한 Case를 나열해보면,

  • 특정 namespace에 기동하는 모든 pod의 /etc/hosts에 'ip address + domain name'을 Patch하기
    더 구체적으로 설명하면, Pod의 Deployment를 위한 원본 YAML(Manifest)에 일괄적으로 'hostAliases' item을 추가하는 기능이 필요했고, 이 기능을 Mutating Webhook 서버에 개발했다.
  • 사내에서 사용하는 운영 관리용 Container(EMS, O&M Container)를 모든 Pod에 Inject하기
    더 구체적으로 설명하면, Pod의 Deployment를 위한 원본 YAML(Manifest)에 일괄적으로 Sidecar Container를 Patch하는 기능을 수행하도록 Mutating Webhook 서버를 개발했다.
  • 특정 조건(namespace, labels)을 만족하는 Pod가 있는 검사하여, 해당 Pod에만 /my_volume/pkg 같은 storage를 Mount하도록 원본 Menifest를 Patch하기

 

Admission Controller와 Mutating WebHook의 개념 및 동작 원리

 

## TODO:  이 부분은 작성 중... (언제 그림을 그리고 글을 작성하나 ~~~, 2021년이 끝나기 전에 작성을 마무리해야 할텐데 ㅠㅠ)

 

 

 

Practical Practice (실전 예제)

실제 동작하는 그럴 듯한 Mutating WebHook Server의 code를 작성해보자.

Mutating WebHook Server를 구현하기 위한 Programming language는 아무거나 사용해도 상관없지만, 나는 Golang이 편해서 Golang을 예제 코드를 작성했다.

처음부터 모든 코드를 작성할 필요가 없다. 아래 stackrox 라는 github repository에 완성도가 높고, 간단하게 만들어 놓은 예제 코드가 있니, 이 Example Code를 git clone해서 사용하면 된다.

https://github.com/stackrox/admission-controller-webhook-demo

 

GitHub - stackrox/admission-controller-webhook-demo: Kubernetes admission controller webhook example

Kubernetes admission controller webhook example. Contribute to stackrox/admission-controller-webhook-demo development by creating an account on GitHub.

github.com

$  git clone https://github.com/stackrox/admission-controller-webhook-demo.git

admission controller webhook server 예제는 README.md가 잘 되어 있고,

deploy.sh 스크립트만 돌려도 완벽하게 Example 시나리오가 동작하기 때문에 쉽게 배울 수 있다.

 

Mutating WebHook Server를 Pod 형태로 배포하기 위한 작업

Helm Chart 작성하기

WebHook 조건 설정하기

 

 

Reference

https://github.com/stackrox/admission-controller-webhook-demo

 

GitHub - stackrox/admission-controller-webhook-demo: Kubernetes admission controller webhook example

Kubernetes admission controller webhook example. Contribute to stackrox/admission-controller-webhook-demo development by creating an account on GitHub.

github.com

 

반응형

Kubernetes cluster(쿠버네티스 클러스터)를 구축하는 것을 도와주는 여러 도구(kubeadm, kubespray, kops)가 있다.

이 문서에는 그런 kubernetes cluster 구축 도구 중에서 kubeadm을 이용하여 kubernetes cluster를 구축하는 방법을 설명한다.

참고로, 이 문서를 작성하는 시점은 2021년 6월 30일이고, 오늘 Kubernetes cluster를 구축하면서 이 문서에 그 구축 과정을 기록한 것이다.

 

Kubernetes Cluster 구축을 위한 계획하기

CentOS 7.9를 설치한 Master node와 Worker node를 준비한다.

Master Node: 1개 (master-0)

Worker Node: 2개 (worker-0, worker-1)

 

 

Master Node와 Worker Node 준비 작업

master node와 worker node 모두에서 아래의 작업을 수행한다.

kubernetes는 iptables를 이용하여 pod간 통신을 가능하게 한다. 따라서 iptables가 정상 동작하도록 하기 위해 아래와 같이 설정한다.

$  sudo modprobe br_netfilter

$  lsmod | grep br_netfilter
br_netfilter           22256  0
bridge                151336  1 br_netfilter

$  cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

$  cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$  sudo sysctl --system

 

모든 master node, worker node에서 swap 영역을 비활성화한다.

$  sudo sed -i '/swap/d' /etc/fstab
$  sudo swapoff -a
$  free -h
              total        used        free      shared  buff/cache   available
Mem:            15G        1.0G         13G         13M        925M         14G
Swap:            0B          0B          0B
$

 

방화벽(Firewalld)를 비활성화한다.

(원칙은 kubernetes가 사용하는 service port만 allow 설정해야 하지만, 여기서는 간단하게 firewalld를 종료하는 것으로 하겠다)

$  systemctl stop firewalld
$  systemctl disable firewalld

 

Docker Engine 설치 (Installing Container Runtime)

container runtime에는 containerd, CRI-O, Docker 등 다양한 SW가 있지만, 이 문서에서는 Docker 제품을 설치한다.

참고: https://kubernetes.io/docs/setup/production-environment/container-runtimes/#docker

 

Old version의 Docker engine을 제거한다.

$  sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

 

Docker 패키지가 있는 Yum Repository를 추가한다.

 $  sudo yum install -y yum-utils
 
 $  sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

 

Docker engine을 설치하고, 기동한다.

$  sudo yum install -y docker-ce docker-ce-cli containerd.io

$  sudo systemctl start docker

# 아래와 같이 'hello-world' container image를 다운로드해서 docker engine이 정상 동작하는지 확인한다.
$  sudo docker run hello-world

 

Container의 Cgroups에 관한 설정 내용을 추가한다.

$  sudo mkdir /etc/docker
$  cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2", 
# 만약 Private container image registry으로부터 `docker image pull`을 하고 싶다면,
# 아래와 같이 'insecure-registries' 항목에 private container image registry의 주소를 추가한다.
# 이렇게 하면, 별도의 Certificate 없이 docker client가 container image registry에서
# container image를 pulling할 수 있다.
  "insecure-registries": ["10.10.3.33:8080", "my-harbor.sejong.space:8080"]
}
EOF

 

Docker engine을 재시작한다.

$  sudo systemctl enable docker
$  sudo systemctl daemon-reload
$  sudo systemctl restart docker

 

여기까지 설명이  master node, worker node에서 준비해야 할 작업이다.

이 다음 설명부터 실제 kubernetes cluster를 구축하기 위한 작업이다.

 

 


 

kubeadm, kubelet, kubectl 설치

kubeadm: kubernetes cluster를 구축하기 위한 명령 도구

kubelet: master node, worker node에서 데몬 프로세스로 기동되어 있으면서, container와 pod를 생성/삭제/상태를 감시한다.

kubectl: 사용자가 kubernetes cluster에게 작업 요청하기 위한 명령 도구 (예를 들어, 'pod를 생성해달라!'  'pod의 개수를 늘려달라!' 같은 사용자 명령을 kunernetes API server에게 전달)

 

아래의 명령을 따라 하여 kubeadm, kubelet, kubectl 명령 도구를 설치한다. (모든 장비에서 수행해야 함)

# 아래 명령을 모든 'Master node, Worker node'에서 수행해야 한다.

$  cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

# Set SELinux in permissive mode (effectively disabling it)
$  sudo setenforce 0

$  sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

$  sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

$  sudo systemctl enable --now kubelet

 

Kubernetes Cluster 생성하기

아래 명령을 master-0 node에서 수행한다.

# 반드시 `master-0` node에서만 수행해야 한다.
$  kubeadm init --pod-network-cidr=10.244.0.0/16
...
...

# 위 명령은 2분 ~ 3분 정도 소요된다.
# 꽤 오랜 시간이 걸리니까, 인내심을 가지고 기다려야 한다.
# 
# 그리고 위 명령의 출력 내용 중에서 아래의 내용을 복사하여 명령행에 붙여 넣고 수행해야 한다.
# (참고: 이 문서의 뒷 부분에서, 아래 설정 파일 'admin.conf'를 이용해서 
#       Kubernetes cluster 외부에서 Kubernetes API 서버에 접속하는 방법을 설명할 것이다)

$  mkdir -p $HOME/.kube
$  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$  sudo chown $(id -u):$(id -g) $HOME/.kube/config

위 명령을 수행하고 바로 Container Network Interface(CNI) 설치하는 작업을 수행해야 한다.

 

CNI 설치

CNI에는 많은 종류가 있지만, 사용하기 쉽고 대중적인 Calico 또는 Flannel CNI를 설치하겠다.

(A) CNI로써 Calico를 설치하는 경우  <-- 추천

$  kubectl apply  -f https://docs.projectcalico.org/manifests/calico.yaml

(B) CNI로써 Calico를 설치하는 경우 <-- 나는 개인적으로 별루~  (몇달 운영하다보면, Error  발생한 경험이 있어서)

$  kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

 

위 CNI 설명 명령이 수행된 후, 아래와 같이 Pod의 기동 여부를 확인한다.

$  kubectl get pod -A
NAMESPACE     NAME                                                 READY   STATUS    RESTARTS   AGE
kube-system   coredns-558bd4d5db-4qglz                             1/1     Running   0          117m
kube-system   coredns-558bd4d5db-znw7h                             1/1     Running   0          117m
kube-system   etcd-master-0.kube.namiso.space                      1/1     Running   0          117m
kube-system   kube-apiserver-master-0.kube.namiso.space            1/1     Running   0          117m
kube-system   kube-controller-manager-master-0.kube.namiso.space   1/1     Running   0          117m
kube-system   kube-flannel-ds-wnbjv                                1/1     Running   0          115m
kube-system   kube-proxy-8gsdl                                     1/1     Running   0          117m
kube-system   kube-scheduler-master-0.kube.sejong.space            1/1     Running   0          117m
$

 

※ 참고

위 명령 `kubectl apply -f .......calico.yaml` 을 수행 후 CNI 설치에 문제가 있었다면, Pod 'coredns-xxxxxx'  구동하지 못하고 'pending' 상태로 남게 된다.

그런 경우는 대부분 `kubeadm init --pod-network-cidr=10.244.0.0/16` 명령을 수행했을 때 사용했던 CIDR 값이 master node, worker node의 물리 주소와 겹치는 경우에 문제가 발생한다. 따라서 '10.244.0.0/16' 값이 아닌 다른 값으로 다시 변경해서 kubernetes cluster를 생성해보면 문제가 해결될 수 있다.

 

Worker node joining

위에서 `kubeadm init --pod-network-cidr=10.244.0.0/16` 명령을 수행했을 때, 출력되었던 메시지 중에 `kubeadm join ....` 과 같은 형태의 메시지가 있었을 것이다. 그 메시지를 복사해서  모든 worker node에서 수행한다.

# worker-0, worker-1에서 아래의 명령을 수행한다.
kubeadm join 10.10.12.39:6443 --token pdfjgjas.psdfjbh kajsdjhasdfv \
    --discovery-token-ca-cert-hash sha256:3nasklj46kj234k5lj12k3j4gkfdjjgdsfh51a3a686

위 명령이 수행된 이후에 master-0 node에서 아래의 명령으로 cluster 구축된 결과를 확인한다.

$  kubectl get node
NAME                         STATUS   ROLES                  AGE    VERSION
master-0.kube.sejong.space   Ready    control-plane,master   3m     v1.21.2
worker-0.kube.sejong.space   Ready    <none>                 1m     v1.21.2
worker-1.kube.sejong.space   Ready    <none>                 1m     v1.21.2

 

Kubernetes cluster 삭제 (Tear down)

만약 깔끔하게 kubernetes cluster를 지우고, 처음부터 다시 구축하고 싶다면 아래와 같이 cluster를 reset 한다.

$  kubeadm reset;   rm -rf  $HOME/.kube  /etc/kubernetes;   rm -rf /etc/cni

 

 

Bastion Node 설정

위 설명에서는 kubectl 명령을 master-0 node에서 수행했다.

그러나 일반적으로 master-0에 직접 SSH 접속해서 kubectl 명령을 수행하는 것을 권장하지 않는다.

kubernetes cluster node는 운영 node이기 때문에 개발자가 접속하는 것이 바람직하지 않다.

(어쩌면, 보안 규정상 개발자가 master node에 SSH 접속하는 것 자체를 허용하지 않는 회사도 있을 것이다)

따라서 master-0 node가 아닌 본인의 PC(예를 들어 MacBook 같은 PC)에서 접속하는 방법을 사용하는 것을 권장한다.

방법은 간단하다.

master-0 node에 있는 /etc/kubernetes/admin.conf 파일을 내 PC(예를 들어 Macbook)에 복사하기만 하면 된다.

# MacOS를 사용한다고 가정하고 설명하겠다.
$  mkdir -p $HOME/.kube
$  cd $HOME/.kube
$  master-0 node의 '/etc/kubernetes/admin.conf' 파일을 내 PC로 내려받는다.
$  mv  admin.conf  config

# 내 PC에서 Kubernetes cluster의 API 서버로 잘 접속하는지 아래와 같이 명령을 수행해본다.
$  kubectl get node
NAME                         STATUS   ROLES                  AGE    VERSION
master-0.kube.sejong.space   Ready    control-plane,master   128m   v1.21.2
worker-0.kube.sejong.space   Ready    <none>                 126m   v1.21.2
worker-1.kube.sejong.space   Ready    <none>                 126m   v1.21.2
$

 


 

이 아래 부분에서 설명하는 작업 절차는 Kubernetes를 운영하는 데 있어서 꼭 필요한 것은 아니고, Web Dashboard로 좀 더 예쁘게 Kubernetes cluster를 모니터링하고 싶은 경우에 아래 Web Dashboard 설정 작업을 해주면 좋다.

 

Kubernetes Web Dashboard 설치 및 설정

내가 참고했던 Web docs(https://waspro.tistory.com/516) 가 있고, 이 문서에서 설명한 3가지 방식 중에서 3번째 방식(Kubernetes API Server 연동 방식)을 사용하는 것을 권장한다.

이 Web Docs에 설명이 잘 되어 있어서 내가 별도 설명할 필요 없을 것이고, 내가 수행했던 명령만 로그로 남겨보겠다.

 

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

# Service Account 생성

$  cat <<EOF | kubectl create -f -
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: admin-user
   namespace: kube-system
EOF
$

# ClusterRoleBinding을 생성

$  cat <<EOF | kubectl create -f -
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   name: admin-user
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
   name: cluster-admin
 subjects:
 - kind: ServiceAccount
   name: admin-user
   namespace: kube-system
EOF
$

# 사용자 계정의 Token 확인
$  kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') 
Name:         admin-user-token-p9ldd
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name=admin-user
              kubernetes.io/service-account.uid=041cb7ec-946a-49b6-8900-6dc90fc08464

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InFmdGVUUnB6QmhoOHhlSDBJLUNLVHlEWWxpd2ZVaDhBVjZOQXE5TElhVWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLWZ2dG5uIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjOGExZTY3MS00NmY1LTQwZjctODNkYy02YTE4N2NiYzkzYmYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.lKKD4yEvlpFJ7-BNuPTyO3YRuFYYdQMgPX5azXwn4bZiki2Y886k1dnNM16L4YuA_SSahrPtitSzPfevlAoeC5msdDg1DKRdFuGuYkkI_u_KvOv7orMopDDgZs0zuXFrHIZa1-qiWbgvHfgokOMvndchCcMHyo8pKD3vdBAq_AxtGlCIPImkfALM_d41FrBKIXEjdoCcHkPu7Cz13UAxNRBRs-d274g2UNz-MUnNiomDhJlcYFXTXeooKjHhUiyoFLCgP-V6Wh_1QSCwdfYZGQ1bF0QcZINQZdwluyOtP43AjXHxdSBrAGIPfaY7qsBR_b2upuUDnQsA1w7qkaQB0g     <== 이 빨간색 token을 Web dashboard login 화면에 붙여 넣고, "Sign-in" 버튼을 누른다.
$

 

위와 같이 ServiceAccount와 ClusterRole을 설정하고, secret을 생성/등록한 후에 Web Browser에서 접속하면 된다.

 

접속 주소 예시:  http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

 

 

 

 

Troubleshooting & How to clear the issue

kubeadm join  명령이 실패하는 경우.

대부분 master node에서 생성한지 1시간이 초과된 token 값을 이용해서 worker node에서 join하려고 하면 

'kubeadm join' 명령이 실패한다.

worker node 1, 2, ... 9 이런 식으로 순차적으로 작업하다가 보면, 거의 끝 부분에 있는 worker node 9는 이미 1 시간이 지난 뒤에

'kubeadm join'을 하게 되므로 종종 실패하게 된다.

그러나 심각한 문제는 아니고, master node에서 'kubeadm token create ...' 명령을 사용해서 다시 token 값을 생성해주기만 하면 된다.

아래와 같이 master node에서 token create하고, worker node에서 새로 만들어진 token 값으로 `kubeadm join'하면 된다.

## On master node.
$ kubeadm token create --print-join-command
kubeadm join 10.10.3.33:6443 --token z53s7g.aa...zc --discovery-token-ca-cert-hash sha256:372...3a686


## On worker node.
$ kubeadm join 10.10.3.33:6443 --token z53s7g.aa...zc --discovery-token-ca-cert-hash sha256:372...3a686
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
$


## 위와 같이 worker node의 joining이 성공하면, 
## 그 동안 activating (auto-restart) 상태였던 kubelet에 아래와 같이 active(running) 상태로 바뀐다.
## On worker node.
$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Thu 2021-11-11 15:38:54 KST; 17s ago
   ...
   ...
 $

위와 같이 Active: active (running) 상태로 출력되면, 정상적으로 kubelet이 기동되고 Master node와 연동된 것이다.

 

반응형

처음으로 golang builder를 설치하고, App 개발을 시작하려면 App 개발을 위한 최상위 폴더를 생성해야 한다.

그리고 그 최상위 폴더에서 아래와 같이 초기화 작업을 해야 한다.

 

$  go mod init  andrew.space/myapp

# 위 명령에 대한 에러가 없다면, 아래의 명령을 수행한다.
# .go source code를 수정했다면 아래 명령을 수행할 것을 권한다.
# 왜냐고? .go에서 사용된 pkg 파일을 자동으로 찾아서 download해주기 때문이다.
$  go mod tidy

 

Go 언어 예제를 작성한다.

 

package main

import "fmt"

func main() {

    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }

    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")
    }
}

 

위 예제 코드를 빌드한다.

 

$  go mod tidy

$  go build

$  ls
go.mod   main.go  myapp*

$  ./myapp
7 is odd
8 is divisible by 4
9 has 1 digit

$

+ Recent posts