50명의 사람들의 일상이 맞추어진 퍼즐처럼 엮여있는 책이다. 읽으면서 내 주변 사람들의 생각도 많이하게 되었는데,

내 가족, 친구, 회사 동료들은 나와 함께하지 않는 순간들에는 어떤 이야기로 살아가고 있을지도 상상하게 되었다.

사실 우리는 나를 중심으로 생활하고 생각하지, 내가 아닌 근처에 있는 타인의 삶을 이야기를 상상하기는 어렵고, 그럴 동기조차 없기 때문이다.

 

이호

슈크림 선생님이라 불리는 이호 할아버지는 내가 닮아가고 싶은 모습을 하고 있었다.

 '지금껏 너무 많이 가졌으니 잃어도 좋다'

비로소 스스로에 대한 만족과 행복을 느끼고 있는 사람이 할 수 있는 말이지 않을까 생각한다.

의사가 되고싶은 아이에게 운을 나누어주겠다며 악수를 청하는 할아버지,

나 또한 그런 여유를 가지고 살기위해 노력 해야겠다.

 

진선미

문영린 에피소드에서 진선미는 새엄마로서 등장한다.

또, 누군가의 아내로서 등장하며,

누군가의 고객이자, 함께 일하게 될 비즈니스 관계로 등장하게 된다.

사실 진선미라는 존재를 알게 되며, 이 사람에 대해 내가 기억을 못하는 것인지,

이 사람을 자세히 알아보기 위해(?) 책의 차례를 다시 되짚어보고 이름을 꼼꼼히 어디있는지 살펴보았지만 놀랍게도 꽤나 여러 이야기에 등장하는 것 치고는 본인의 에피소드가 수록되지 않는 인물이었다.

아마 진선미는 T일 것이고, 자유분방하며 나이스한 성격이다. 누구에게도 자신의 생각을 잘 전달할 수 있는 사람이고 자신의 단단한 가치관 아래 자유롭게 세상을 살아가는 진선미라는 인물은 굉장히 즐거워보인다. 지향하고싶은 삶을 가졌다고 해야할지..

특히 새엄마로서 매우 이성적인 어조로 조언하는 이야기는 나도 뜨끔하게 만들었다. ㅎㅎ

"마음은 내가 어떻게 해줄 수 있는 문제가 아니고 네가 크면서 해결해야겠지만, 몸무게 때문에 더 힘들면 그건 지금 해결해보자. 돈으로 못 빼는 살이 어딨니?"

 

이 책은 어 이사람 아는 사람인데..? 하고 그 사람이 다시 궁금해져 다시 책의 이곳저곳을 넘겨보게 만든다. 액자식 구성을 독자에게 맡긴 책 같다고해야 하는지 모르겠다. 개성있고 재미있게 읽고, 이러한 이유로 읽는데 참 오랜 시간이 들은 책이다. 인상깊었다! :)

 

 

그리고... 인물간의 관계도를 그려야 겠다고 생각을 하기도하였는데

똑똑한 독자들이 이미 만들어놓았다...

'독서' 카테고리의 다른 글

[독서] 나는 매주 시체를 보러 간다  (0) 2024.04.01
쇼코의 미소  (0) 2024.03.25

 

<그것이 알고싶다> 애청자이기도 한 나는 이 책의 저자가 법의학 분야에서 매우 저명한 사람인걸 알고 있었다. <그것이 알고싶다>에 출연하는 유성호 교수는 의학적인 측면에서 사인을 분석하고 시체에서 말해주는 이야기를 우리에게 전해주는 역할을 한다.

이 책은 일종의 어떠한 죽음을 맞이할 것인지 나의 죽음을 어떻게 준비할 것인지에 대한 고민거리를 던져준다. 대부분의 사람들은 죽음에 대한 준비 없이, 사회가 마련해둔 틀 안에서 맞이하게 된다. 50%를 초과하는 사람들이 본인의 집에서 죽기를 희망하지만, 대부분의 경우 별 준비없이 병원에서 의사가 생명연장을 시도하거나, 약물투여를 통해 연명하다가 죽게된다. 이게 정말로 우리가 바라는 죽음의 모습일까?

나는 지금까지 태어난 이후로 나의 죽는 과저에 대해서 진지하게 생각해본 적이 없다. 그 이유는 아마 죽음이라는 것 자체가 부정적이고, 회피하기 싫은, 거부감이 드는 단어라는 이유 때문일 것이다. 그러나 죽음은 사람으로 태어났으면 절대적으로 경험해야 할 피할 수 없는 것이다.

저자는 가족들에게 미리 자신의 장례가 어떻게 이루어졌으면 좋겠는지, 재산이나 금전적인 것은 어떻게 처리해야 할지 디테일하게 전달될수록 준비하는 가족들의 입장에서도 부담이 없고 좋다고 한다. 전혀 생각지도 못한 부분들이었기에 읽으면서 당황스러웠다. 내가 뇌사 상태에 빠진다면, 나는 그럼에도 불구하고 생명을 유지하기를 원할까...? 아마도 아닐 것 같다. 뇌가 죽었는데, 몸에 에너지만 공급해준들 그게 과연 나는 살아있다고 볼 수 있는걸까. 이러한 문제는 이를 결정할 가족들에게도 굉장히 부담스러운 딜레마로 다가올 것 같다는 생각이 들었다. 가족들의 선택에 따라 죽음이 결정되는 것은 너무 괴로운일 일테니까

책을 읽으며 죽음에 대한 여러가지 사회적 문제에 대해서도 깨닫게 되었다. 사람은 언제부터 사람으로서 인정받는 걸까? 엄마의 배속에서 나오는 순간? 수정란이 착상하는 순간? 이 밖에도 줄기세포에 대한 과학연구 분야의 윤리적 논쟁들.. 그뿐만이 아니다, 본인이 스스로 죽는 행동에 대해 어떠한 시각으로 판단해야 할지에 대한 것도 매우 심각한 이슈다. 내가 말하는 스스로 죽는 행동이란 치료를 해서 더 이상 의미있는 개선이 없을 것이라 판단 될 때 환자들이 본인의 운명을 선택하거나, 질병이 아니더라도 스스로의 환경에 대해 비관하고 죽는 행동을 의미한다.

미성숙한 생각이었다면, '본인의 선택인데 왜 문제인 걸까?'라고 되물었을지도 모른다. 그러나 책에서 설명한 사례와 연구에 따르면, 투신으로써 스스로 죽는 행동을 선택하였다가 살아난 사람의 인터뷰 내용으로 "그 순간, 나는 죽고 싶지 않았다"라고 말했으며, 고통받는 환자들이 안락사를 위해충분한 의사의 정신적 상담 및 동의를 구하고 스스로 죽는 행동을 위한 버튼을 제공했을 때, 결국 끝내 버튼을 누르지 못하는 자들은 약 60%가 넘는다고 한다. 사실 모두 죽고 싶어하지 않는다. 스스로 죽는 행동에 대해 우리는 단순히 본인의 선택이니 자유라거나, 종교적 이유로 어떠한 경우에도 절대 허용할 수 없다는 것은 사회적인 관점에서 본다면 지극히 1차원적 의견이며, 분명 그에 따른 부작용을 낳는 방향성일 것이다. 이러한 복잡한 인간의 존엄성, 생명에 대한 윤리적 문제는 국가마다의 국민들의 문화, 인식에 따라 달라지고 시대적 변화에도 민감하게 반응하여 끊임없이 변화한다.

나의 죽음은 어떻게 이루어져야 나의 마지막이 아름다울까, 그리고 만일 안락사가 고려해야 할 정도로 내가 극심히 고통받고 치유불가한 상태라면 어떤 선택을 해야 할까

'독서' 카테고리의 다른 글

피프티피플  (1) 2024.04.28
쇼코의 미소  (0) 2024.03.25

큐를 이용해서 구현하며, 기본적인 BFS 탐색 순서는 다음과 같다.

1. 큐를 하나 만든다

2. 시작할 노드를 넣는다

3. 시작할 노드를 꺼내고 출력한다

4. 인접한 노드를 큐에 넣는다

5. 이 때, 한번 큐에 넣었던 노드는 다시 큐에 넣지 않아야 한다

 

BFS 관련된 문제로 소스코드로 확인해보자

백준 토마토 문제이다.

https://www.acmicpc.net/problem/7569

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,

www.acmicpc.net

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main{
    public static int N, M, H;
    public static int[][][] box;

    public static int[] dx = {1, -1, 0, 0, 0, 0};
    public static int[] dy = {0, 0, 1, -1, 0, 0};
    public static int[] dz = {0, 0, 0, 0, 1, -1};

    public static Queue<Tomato> queue = new LinkedList<Tomato>();

    static class Tomato {
        int x, y, z;

        public Tomato(int x, int y, int z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }

    }

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        M = Integer.parseInt(st.nextToken());
        N = Integer.parseInt(st.nextToken());
        H = Integer.parseInt(st.nextToken()); /** 1번 문제는 변수 H를 1로 주면 해결된다.. */

        box = new int[H][N][M];

        for (int k = 0; k < H; k++) {
            for (int i = 0; i < N; i++) {
                st = new StringTokenizer(br.readLine(), " ");
                for (int j = 0; j < M; j++) {
                    box[k][i][j] = Integer.parseInt(st.nextToken());
                    if(box[k][i][j] == 1){
                        queue.offer(new Tomato(i, j, k));
                    }
                }
            }
        }

        bfs();
    }

    static int isPerfectlyRipe () {
        int max = -10000000;
        for (int k = 0; k < H; k++) {
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (box[k][i][j] == 0) {
                        return 0;
                    }
                    max = max > box[k][i][j] ? max : box[k][i][j];
                }
            }
        }
        return max;
    }

    public static void bfs() {

        while (!queue.isEmpty()) {
            Tomato tomato = queue.poll(); // 큐에서 익은 토마토를 하나 꺼내자

            for (int i = 0; i < 6; i++) { // 상하좌우위아래 6개 방향으로 이동했을 때의 각 토마토 확인
                int _x = tomato.x + dx[i];
                int _y = tomato.y + dy[i];
                int _z = tomato.z + dz[i];
                if(0 <= _x && _x < N &&
                        0 <= _y && _y < M &&
                        0 <= _z && _z < H) { // 이동한 장소가 배열의 크기를 벗어나지 않도록 해야한다
                    if (box[_z][_x][_y] == 0) { // 아직 안익었다면 큐에 넣어준다
                        box[_z][_x][_y] = 1; //이제 익었으니까 1로 변환해주어야 다음 탐색을 이어나갈 수 있다
                        queue.add(new Tomato(_x, _y, _z));
                        box[_z][_x][_y] = box[tomato.z][tomato.x][tomato.y] + 1; // 날짜정보를 저장해준다 이 정보는 1부터 시작했으니 결과에서 1을 빼주어야한다
                    }
                }
            }
        }

        System.out.println(isPerfectlyRipe() - 1);

    }
}

 

 

이 책에서는 쇼코의 미소를 포함한 작가의 여러 중단편작 7편을 다룬다.

내용의 전개가 확 끌려들어간다던가 등의 느낌은 아닌 서정적인 분위기의 책인데, 장면에 대한 묘사는 그 장소와 분위기를 보다 생생하게 상상하게 만든다.

작가는 사회적인 여러 이슈들을 책에 잘 녹여내서 우리에게 생각할 거리들을 안겨준다. 나는 특히 이데올로기에 대해 표면적으로만 생각을 했었는데(정책이나, 정치적 성향이나... 등등), 그 안에서 살아가는 우리들의 모습에 투영되었을 때, 누군가에게는 큰 아픔이나 상처가 될 수 있다는 생각이 들었다. 작용이 있으면 부작용이 뒤따르는 법이다...

일부 몇개의 작품에서는 만남, 이별, 재회, 그리고 먼 훗날의 회상을 그리는 패턴을 가지는데, 재회의 과정에서는 항상 슬픈 감정이 들었다. 그 까닭은 그동안 생각했던 상대에 대한 긍정적인 모습이 모조리 부정되고, 미워지거나 다소 혐오스럽다는 불편한 감정이 들도록 함에 있다. 이 과정에서 상대에게 우월감을 느낀다던지, 이전과는 다른 내가 상대를 대하는 마음에 대해 너무나도 현실적으로 표현했기에 인간의 본성을 잘 그려냈다고 생각했다.

 

그때만 해도 나는 내가 다른 사람들과는 다른 삶을 살 수 있으리라고 생각했다. 나는 비겁하게도 현실에 안주하려는 사람들을 마음속으로 비웃었다. 그런 이상한 오만으로 지금의 나는 아무것도 아니게 되어버렸지만, 그때의 나는 삶이 속물적이고 답답한 쇼코의 삶과는 전혀 다른, 자유롭고 하루하루가 생생한 삶이 되리라도 믿었던 것 같다.

 

투이가 내게 선물한 스누피 만화책은 아직도 내 방 책장에 있다. 흑백 만화책이지만 우드스탁만은 샛노란색으로 칠해져 있다. 제대로 날지도 못하는 카나리아 우드스탁. 책을 펼쳐 그 노란색 카나리아를 볼 때면, 한 장 한 장 책장을 넘겨가며 그 작은 새에게 색을 입혀주려 했던 투이의 따듯한 마음이 가까이 다가왔다.

 

어쩌면 쇼코가 펜팔 친구(소유와 소유의 할아버지)를 친구로서 인정하고, 가까이 있는 사람들을 멀리하려던 이유는 가까이 있는 사람일 수록, 나의 내면을 드러냈을 때 더 큰 상처를 입히기 쉬운 사람들이어서가 아니었을까 싶다. 그런 두려움이 있어서 자신을 지켜주는, 그래서 보호하고픈 할아버지도 표면적으로 거리를 두고자했을거라 추측해본다.

'독서' 카테고리의 다른 글

피프티피플  (1) 2024.04.28
[독서] 나는 매주 시체를 보러 간다  (0) 2024.04.01

2.1 컨테이너 애플리케이션 개발의 흐름

스텝1 개발 환경의 준비

-       에디터나 IDE 등을 설치하고 개발 언어별로 필요한 런타임이나 라이브러리 도입

스텝2 컨테이너 이미지의 작성 및 공유

-       컨테이너 작동을 하려면 애플리케이션을 움직이기 위해 필요한 바이너리, OS, 네트워크와 같은 ㅇ니프라 설ㅈ어이 모두 포함되어 있는 컨테이너 이미지를 작성해야 한다. 도커의 경우 DOCKERFILE이라는 텍스트 파일에 구성을 기술, 그것을 빌드한 것을 실행 환경에서 이용가능한 레포지토리로 공유한다.

스텝3 클러스터 작성 (실제 환경의 작성)

실제로 컨테이너 애플리케이션을 작동시키는 서버를 셋업한다.

개발 환경이나 테스트 환경에서는 로컬 머신에서 작동시킬 수도 있지만 서비스를 공개할 때는 자신이 보유한 온프레미스 환경에서 시스템을 구축하거나 클라우드 서비스를 이용한다.

 

2.2 개발 환경 준비

Visual studio code 설치

MS가 제공하는 오픈소스 소스코드 에디터이며 무료이다. Windows, macOS, Linux에서도 작동된다.

비주얼 스튜디오 마켓플레이스에서 제공하는 확장 기능을 넣어 커스터마이징하여 사용 할 수 있다.

 

Vs code 주요 지원기능

-       디버그 기능

-       구문 하이라이트

-       intelliSense(입력 보완 기구)

-       Git 연동

-       태스크 자동 실행

-       확장 기능 임베디드

-       통합 터미널 가능

Vs code에서 [view] -> [extensions]

Docker support for visual studio 설치

Visual studio code kubernetes tools 설치

 

Azure CLI 명령의 설치

https://aka.ms/installazurecliwindows

CMD를 통해 AZURE에 로그인한다

as login

 

이어서 다음 명령을 실행하여 리소스 프로바이더를 활성화한다.

az provider register -n Microsoft.Network

az provider register -n Microsoft.Storage

az provider register -n Microsoft.Compute

az provider register -n Microsoft.ContainerService

 

-       Azure cli 설치 문서 : https://docs.microsoft.com/ko-kr/cli/azure/install-azure-cli

-       Kubectl 명령의 설치 : https://storage.googleapis.com/kubernetes-release/release/v1.11.4/bin/windows/amd64/kubelctl.exe

 

설치후 버전 체크

$ kubectl version

 

Azure cli를 이용하면 az명령어로 kubectl 명령을 설치 할 수 있다. Azure의 경우 이 방법으로 진행한다.

Sudo az install-cli

 

Azure cloud shell은 브라우저에서 azure를 명령으로 조작할 수 있는 웹 애플리케이션이다. 클라이언트 단말이나 az명령을 설치하는 것이 어려운 경우에 사용하면 좋다.

개요 : https://docs.microsoft.com/ko-kr/azure/cloud-shell/overview

 

2.3 azure container registry

Azure Container Registry(이하 ACR)는 애져가 제공하는 컨테이너 이밎 공유 서비스다. 쿠버네티스 뿐만 아니라 DC/OS, Docker Swarm, Azure가 제공하는 컨테이너 실행 환경에서 이용할 수 있다.

 

(1)   레지스트리 작성

$ ACR_NAM=sampleACRResgistry

Azure에서는 리소스 그룹이라는 논리적 단위로 리소스를 관리한다.

$ ACR_RES_GROUP=$ACR_NAME

 

그리고 다음 명령어를 통해 리소스 그룹을 작성한다 로케이션은 한국 중부 리전을 사용한다.

$ az group create –resource-group $ACR_RES_GROUP –location koreacentral

 

이제 리소스 그룹이 생성되었으니 acr의 레지스트리를 작성한다.

$ az acr create –resource-group $ACR_RES_GROUP –name $ACR_NAME –sku Standard –location koreacentral

여기서 LOGIN SERVER의 값을 확인해야 한다. 이것이 컨테이너 레지스트리의 액세스 위치가 된다.

 

(2)   샘플 다운로드

예시에서는 아래와 같은 샘플 프로젝트를 사용한다

$ git clone https://github.com/ToruMakabe/Understanding-K8s

$ cd Uderstanding-K8s/chap02/

 

(3)   이미지 빌드

다음 명령어를 통해 빌드한다 이미지 이름은 photo-view이며 이미지의 식별을 위해 ‘v1.0’ 태그를 설정한다 이 이미지의 빌드에는 시간이 조금 걸린다.

az acr build –registry $ACR_NAME –image photo-view:v1.0 v1.0/

 

2.4 azure를 사용한 쿠버네티스 클러스터 작성

Azure Kubernetes Service(이하 AKS)를 이용하여 설명을 진행한다

(1) ACR AKS 연결하기

좀 전에 ACR에서 작성한 컨테이너 이미지는 AKS에서 작성한 쿠버네티스 클러스터 상에서 pull하여 움직인다.

그러기 위해서는 ACR AKS 사이에 인증을 해야 하기 때문에 Azure Active Directory의 서비스 프린서플을 사용한다.

서비스 프린 서플이란 azure의 리소스를 조작하는 애플리케이션을 위한 ID이다.

먼저 az acr show 명령을 실행하여 ACR의 리소스 ID를 취득한다. 다음 명령어를 사용하여 취득한 리소스 ID를 쉘 환경변수 ACR_ID에 설정한다.

 

$ ACR_ID=$(az acr show --name $ACR_NAME --query id --output tsv)

 

이후 서비스 프린서플 이름을 쉘 환경변수 SP_NAME에 설정한다.

(2) 클러스터 만들기

(3) 클러스터 연결을 위한 인증 정보 설정하기

 

KUBECTL 명령을 사용한 클러스터의 기본 조작

서비스 프린 서플이란 azure의 리

AKS를 사용하여 쿠버네티스 클러스터를 작성했으면 이제 kubectl 명령을 사용하여 클러스터를 조작할 수 있다.

kubectl은 기본적으로 다음과 같은 구문으로 사용한다.

kubectl  <명령> <타입> <이름> <플래그>

 

  • 명령
    • 클러스터에 대해 어떤 조작을 할지 지정
    • 자주쓰는 명령은 create / apply / get / delete, 상세보기 describe, 로그 확인은 logs
  • 타입
    • 쿠버네티스는 컨테이너 애플리케이션이든 네트워크 설정이든 잡 실행이든 모두 리소스라는 추상화된 개념으로 관리한다
    • 타입에는 단축명 이용할 수 있다
  • 이름
    • 리소스에는 식별을 위한 고유한 이름 존재
    • 이것을 리소스의 이름으로 지정, 이름은 대소문자 구분
    • 이름을 생략하면 모든 리소스의 상세정보가 표시된다
  • 플래그
    • 옵션으로 플래그를 지정한다.

 

 

 

 

'Develop Issue > Kubernetes' 카테고리의 다른 글

1. 컨테이너, 쿠버네티스란?  (1322) 2023.03.19

1.1         컨테이너 기술의 개요

컨테이너란?

컨테이너란 호스트 OS 상에 논리적인 구획(컨테이너)을 만들고, 애플리케이션을 실행시키는데 필요한 라이브러리나 애플리케이션 등을 하나로 모아 그것을 마치 전용 서버인 것처럼 사용할 수 있게 만든 것

 

컨테이너 기술에는 여러 가지가 있지만, 현재 쿠버네티스의 기본값으로 되어 있는 것은 도커(Docker).

 

호스트형 서버 가상화

호스트형 서버 가상화는 하드웨어상에 베이스가 되는 호스트 OS를 설치하고 호스트 OS에 가상화 소프트웨어를 설치한다.

컨테이너와는 달리 호스트 OS상에서 다른 게스트 OS를 작동시키므로 오버헤드가 매우 커진다.

 

하이퍼바이저형 서버 가상화

컨테이너 기술은 애플리케이션의 실행 환경을 모아놓음으로써 이식성을 높이고 스케일러블한 환경에서도 작동하는 것을 지향하고 있다.

 

컨테이너 애플리케이션 개발자의 흐름

(1)  컨테이너 애플리케이션의 빌드

도커는 애플리케이션의 실행에 필요한 프로그램 본체, 라이브러리, 미들웨어나 OS, 네트워크 설정 등을 하나로 모아 도커 이미지를 만든다. 도커의 경우 하나의 이미지에는 하나의 애플리케이션에만 넣어두고

여러 컨테이너를 조합하여 서비스를 구축할 것을 권장한다.

(2)  컨테이너 이미지 공유

컨테이너 이미지는 레시스트리로 공유할 수 있다. 예를들어 도커의 공식 레지스트리인 Docker Hub에서는 UbuntuCentOS와 같은 리눅스 디스트리뷰션의 기본 기능을 제공하는 베이스 이미지가 배포되어 있다.

(3)  컨테이너 애플리케이션의 실행

도커는 리눅스 상에서 컨테이너 단위로 서버 기능을 작동시킨다.

또 도커 이미지로부터 여러 개의 컨테이너를 시작시킬 수도 있다.

 

1.2         쿠버네티스의 개요

분산 환경에서 컨테이너 운용 관리

컨테이너는 개발 환경처럼 한 대의 머신에서 가동시킬 때는 손 쉽게 도입할 수 있다.

하지만 멀티호스트로 구성된 클러스터 구성에서 가동시키려면 컨테이너의 시작 및 정지와 같은 조작뿐만 아니라 호스트 간의 네트워크 연결이나 스토리지 관리, 컨테이너를 어떤 호스트에서 가동시킬지와 같은 스케줄링 기능이 필요하다.

게다가 컨테이너가 정상적으로 작동하고 있는지 아닌지를 확인하는 장치도 필요하다.

이러한 기능을 갖추고 있으면서 컨테이너를 통합 관리할 수 있는 툴을 컨테이너 오케스트레이션 툴이라고 한다.

쿠버네티스, 도커(Swarm 모드), Apache Mesos/Marathon

 

쿠버네티스의 특징

쿠버네티스는 대규모 분산환경에서 소수의 에지니어 만으로 컨테이너 애플리케이션을 관리하는 것을 모걱으로 한 오케스트레이션 툴이다.

쿠버네티스는 하드웨어 인스라스트럭쳐를 추상화하여 데이터센터 전체를 하나의 방대한 계산 리소스로 간주한다. 그 결과 개발자는 실제 서버를 의식할 필요 없이 컨테이너 애플리케이션을 디플로이하여 실행할 수 있다.

 

쿠버네티스의 주요 기능

-      여러 서버에서 컨테이너 관리

-      컨테이너 배포

-      컨테이너간 네트워크 관리

-      컨테이너 부하분산

-      컨테이너 감시

-      컨테이너 업데이트

-      장애 발생 시 자동 복구

이러한 내용들은 선언적 설정과 API 센트릭이 있다.

쿠버네티스에서는 시스템이 원래 되어 있어야할 모습을 정의 파일에 설정하여(선언적 설정) 장애가 발생해도 사람이 개입하지 않고 원래 되어 있어야 할 모습으로 수습할 수 있다.

 

일단 쿠버네티스를 시험해 보고 싶은 경우는 퍼블릭 클라우드가 제공하는 매니지드 서비스를 이용할 것을 권장한다.

Amazon Elastic Container Service for Kubernetes(Amazon EKS)

Google Kubernetes Engine(GKE)

Azure Kubernetes Service(AKS)

 

쿠버네티스의 유스케이스

마이크로 서비스의 운용 관리

쿠버네티스가 갖고 있는 수평 스케일링, 자기 복구, 부하 분산 등과 같은 기능을 활용 할 수 있다. 영구 데이터ㅢ 관리는 컨테이너가 아니라 클라우드의 데이터 관리 서비스를 사용하는 것이 좋다.

 

기계학습의 워크로드

대규모 데이터셋을 사용하는 심층학습의 트레이닝은 파라미터나 서버나 분산 학습을 위한 워커노드를 관리해야 한다. 컴퓨팅 리소스를 많이 필요로하는 워커노드에는 CPU와 같이 고가의 하드웨어를 온디맨드로 할당하도록 제어할 수 있다.

'Develop Issue > Kubernetes' 카테고리의 다른 글

2. 쿠버네티스의 환경 구축  (1392) 2023.03.23

이 취약점으로 주말에 잘쉬고 있다가 갑자기 일을 하게 되었다.. 보편적으로 안쓰는 업체가 찾기 힘든 라이브러리에서 크리티컬한 취약점이 발견된 것이다. 이후에도 지속적으로 개발 커뮤니티에도 해당 이슈가 올라와서 나도 내가 아는바에 대한 내용을 기록으로 남겨본다

 

[개요]

자바 기반으로 만들어지고 전세계적으로, 대중적(?)으로 많이 사용되는 로깅을 위한 라이브러리로 log4j가 있다.

이번 이슈가 된 취약점은 log4j가 넘겨받은 변수를 그대로 로깅하는 것이 아니라 해당 변수를 분석해 실행할 수 있는 lookups 기능에서 발견되었다. lookups란 예를들어 log.error("에러 : " + result); 에서 result가 ${env:PASSWORD}로 설정되어 있다면 "에러 : ${env:PASSWORD}"를 그대로 로깅하는 것이 아니라 이에 해당하는 설정값을 찾아 "에러 : qwer1!"를 로깅하게 되는 기능이다. lookup에는 여러가지 기능들이 있는데, 이번 케이스는 JDNI 룩업을 이용한 공격이 가능하다는 취약점이다. 이른바 Log4Shell 취약으로 불린다.

 

[취약점 공격 대상]

log4j-core 버전 2.10.0 이상 ~ 2.15.0 미만

 

[대응방법]

1. log4j를 2.15.0 이상으로 업그레이드 한다. (Java8 이상에서만 기동된다)

2. log4j 2.10.0 이상 사용 시 다음의 방법 중 한 가지 이상의 방법을 사용한다. 개인적인 의견으로는 서비스의 운영환경마다 다르겠지만.. 운영하는 웹서비스가 많아 관리 포인트가 많고 복잡할 경우.. 이 방법은 관리측면에서는 별로 좋은 방법 같진 않다. 개발자가 프로젝트 소스코드 외부에서 관리해야하고(서버/인프라 단), 이 설정이 되어있는 이유에 대해 나중에 시간이 많이 지나서 누가 보더라도 알 수 있도록 히스토리를 잘 관리해야 한다는 점..

  •  
  • Java 실행 인자(Arguments) 에 시스템 속성을 추가한다. -Dlog4j2.formatMsgNoLookups=true
  • Java 실행 계정의 환경 변수 혹은 시스템 변수로 LOG4J_FORMAT_MSG_NO_LOOKUPS=true를 설정한다.

3. log4j 2.7.0 이상 사용 시 log4j 설정(log4j.xml 등)에 PatternLayout 속성에 있는 %m 부분을 %m{nolookups} 으로 교체한다.

4. 만약 log4j 버전이 2.10.0보다 낮다면, 이번 이슈의 공격대상은 아니다.. 그렇지만 1버전 대의 경우는 지원이 중단되었으며, 이미 RCE 보안이슈가 존재하므로 가급적 업그레이드 방안을 모색하는 것이 좋다

 

[팁]

위 대응방법은 기본적인 조치 방법에 대해 설명한 것이고, 이와 더불어 조치 시 아래 오픈소스를 참고하면 빠르게 조치할 수 있다.

https://github.com/logpresso/CVE-2021-44228-Scanner

 

GitHub - logpresso/CVE-2021-44228-Scanner: Vulnerability scanner and mitigation patch for Log4j2 CVE-2021-44228

Vulnerability scanner and mitigation patch for Log4j2 CVE-2021-44228 - GitHub - logpresso/CVE-2021-44228-Scanner: Vulnerability scanner and mitigation patch for Log4j2 CVE-2021-44228

github.com

해당 소프트웨어를 서버로 옮겨서 웹서비스가 설치된 디렉토리를 중심으로 탐색하면 대상 log4j를 사용중인지 확인 할 수 있다. 사용방법은 해당 레포지토리 README에 상세히 나와있고 매우 간편하다.

 

그리고 우리 서비스 외에도 밴더 솔루션등에도 log4j 이슈가 있을 수 있으니 꼭 문의를 넣어서 확인해보자

이 가이드는 솔라나 지갑을 이미 보유한 상태에서 진행함

1. solona CLI를 설치한다. 아직까지는 연구단계임에따라 윈도우 환경 전용으로 설치하였는데 생각보다 잘 동작한다

2. 다음 명령어에 따라 내 지갑에 연결된 토큰 account 정보를 확인해볼수 있다.

C:\WINDOWS\system32>spl-token accounts
Token                                         Balance
---------------------------------------------------------------
83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ  90
85iewBw7g5xzTBPsmEhRT6UyVHjZKkH2QzxR6Hpxp4AM  10  (Aux-1*)
HuJCd48ycmqS5ADDnprxzbPoTAH2FQwYY92SdFC4tZgs  10  (Aux-1*)

참고로 위 과정 중 특정위치에 있는 계정정보파일을 읽을 수 없다면 에러가 뜰것이다. solona config 명령어를 통해 계정정보가 어디에 저장돼는지 확인 할 수 있으며 계정정보가 없다면 자신의 지갑 개인키를 배열(엄밀히 따지자면 json)의 형태로 저장해주면 된다. (ex. [13, 103, 34, 534 ...] 이런 형태로 저장된다. 이 값은 sollet.io에서 접속한 뒤 자신의 지갑에서 export를 하면 해당 파일을 얻을 수 있다.. 직접 이렇게 변환하는 방법도 알고싶은데 어디에서인지 아직 알 수 없음;

3. 토큰을 새로 생성한다.

intput

spl-token create-token

output

Creating token 83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ

Signature: 4ELSGXv7Eh6sFnzcM7XvVLmZUZrWbCsF7DoKYpj14qmMzohh9b79AqTXnUYTaLKUuFQLASBHrPMKhEbrM7h8cjMr

4. 이제 생성한 토큰을 집어넣을 token account를 만들어준다. 왜이렇게하는건지는 아직 이해하지 못하겠으나... 본 지갑에서 서브형태로(?) 종속된 account를 만들어서 거기에 방금 3에서 생성한 토큰을 넣어줄것이다.

intput

spl-token create-account 83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ

output

Creating account 3mMDq1JaT3jRWyJkK7tZuy9E9jJFCey83Kj2WK6Lk1Ei

Signature: 42Sa5eK9dMEQyvD9GMHuKxXf55WLZ7tfjabUKDhNoZRAxj9MsnN7omriWMEHXLea3aYpjZ862qocRLVikvkHkyfy

5. 새로만든 account를 확인해보자

solana balance 3mMDq1JaT3jRWyJkK7tZuy9E9jJFCey83Kj2WK6Lk1Ei

6. 토큰을 다음과 같은 형태로 민트한다

spl-token mint tokenAddress mintAmount recipientAddress

예시는 아래와 같다

spl-token mint 83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ(토큰) 100(발행량) 3mMDq1JaT3jRWyJkK7tZuy9E9jJFCey83Kj2WK6Lk1Ei(토큰account)

7. 이제 다음과 같이 발행된 토큰을 확인해 볼 수 있다.

spl-token accounts

Token Balance

------------------------------------------------------------

83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ 1000000

8. 발행한 토큰을 다른 지갑으로 전송해본다

spl-token transfer --fund-recipient tokenAddress transferAmount recipientAddres

아래는 예시

input

spl-token transfer 83htTo1jczLTMRBLDjmc94bx7Gz3M3FrpJW2QtVzUZRJ 30 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg

output

Transfer 50 tokens Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg Recipient associated token account: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd

 

 

실수로 merge를 하였을 경우 다음과 같이.. reset을 해버리자

git reset --merge ORIG_HEAD

위 명령어를 사용하면 원격지와의 head와 로컬의 head가 상이하여 push시도시 에러가 발생한다.

git push -f origin master

-f (force)를 사용하여 강제로 push해야한다.

+ Recent posts