추상화( abstraction )
(1) 복잡한 것을 감추는것(Encapsulation) → 보다 효율적인 설계, 구축
(2) 필요한 기능만 오픈하는 것
(3) 인터페이스의 표준화 → 다른 기능, 모듈과 소통
(ex) 언어별 SDK library(개발자가 특정 플랫폼, 서비스, 또는 API와 상호작용할 수 있도록 도와주는 라이브러리 또는 도구 모음)를 전달하는 것보다 서비스 스펙으로 제공한 Restful API를 호출하는 것이 좋음 ( 언어별 통신을 모두 표준화 )
대표적인 추상화 예시
- 네트워크의 추상화 : SDN(software defined network) ⇒ 모든 개체를 묶어서 원하는 네트워크 환경의 스위치로 만듬
- 스토리지의 추상화 : SDS(software defined storage) ⇒ 하나의 디스크인것처럼 만들어줌
- 서버 : VM( virtual machine )
=> 이는 모두 하드웨어를 추상화하는 것임
- 결과적으로 이를 다루고 하드웨어-소프트웨어 사이에 존재하는 OS를 추상화하는 것이 핵심( 가상머신의 방식등.. )
- OS는 공통적으로 리눅스를 쓰는 방식으로 발전( 커널공유 ) = 표준화 당했다!
- 어떤 리눅스라도( any Linux ) 하나의 커널(OS core)을 공유( 배포판에서는 OS 관리 유틸리티만 상이함 ) → 컨테이너구동이 가능( 리눅스 컨테이너 )
- 윈도우에서도 Linux 커널을 가볍게 가상화하여 제공하는 WSL2를 이용하여 리눅스 환경을 제공 → 리눅스 컨테이너실행가능 / Docker Desktop은 WSL2를 기반으로 리눅스 컨테이너 지원
Container
모든 추상화 대상들을 컨테이너에 담아서 추상화
what is 컨테이너? 커널은 공유하고 리소스(하드웨어: CPU, Memory, Disk, Process, Network)를 격리해주는 것!!
how to 컨테이너? ⇒ namespace기술 : 서로 영역을 침범하지 못하게 함
( * 리눅스 컨테이너를 가능하게 하는 기술 : namespace & cgroup )
Cloud native
: 클라우드 환경에서 애플리케이션을 설계, 구축, 실행하는 방식
- 리눅스 운영체제를 바탕 ( 리눅스 컨테이너 )
- Linux Foundation, CNCF의 다양한 기술지원 : 컨테이너 기술(Docker, Containerd) & 클라우드 오케스트레이션 도구(Kubernetes)
- CloudNative 방식
- 격리성 : 컨테이너, 마이크로서비스 아키텍처, 컨테이너 오케스트레이션
- 자동화 : 배포의 자동화 → CI/CD 파이프라인, 인프라관리의 자동화 → Terraform, Ansible
- 확장성 및 복원력 : 불변인프라( immutable )
- 서비스 메시( 마이크로 서비스간의 통신을 관리하고 모니터링 )
하드웨어 관점의 추상화 (가상화) : VM( 가상머신 ) → 인프라 운영에서 용이함
소프트웨어 관점의 추상화 (컨테이너화) : Container( 격리된 환경에서 모든 것을 담음 ) → 서비스 개발, 관리에서 용이함
각 추상화의 목적이 다름
- 쿠버네티스 : 수많은 컨테이너를 다루고 제어하고 관리하기 위한 기술↔ docker swam : 컨테이너를 대규모로 관리하기 위한 기술
- ↔ docker compose : 서비스 제공목적, 내부개발용
- service mesh : 쿠버네티스 위에서 네트워크까지 추상화( 요청까지 추상화 )
핵심 요약
- 클라우드: 인터넷을 통해 제공되는 IT 리소스(서버, 스토리지 등)를 활용하는 환경.
- 가상화/컨테이너화: 클라우드 환경에서 얻은 리소스를 분리된 독립적인 환경(가상 머신/컨테이너)에서 관리하는 방법.
- 도커: 컨테이너를 생성하고 관리하는 도구.
- 쿠버네티스: 컨테이너를 기반으로 서비스를 배포하고 관리하는 오케스트레이션 도구.
마이크로 서비스 아키텍처(MSA)의 특징
마이크로 서비스 아키텍처 = Loosely coupled and High-cohesion service oriented architecture with bounded context
: Loosely Coupled, High-cohesion, bounded context
(1) Loosely Coupled ( 느슨한 연결 )
- 인터페이스를 이용한 통신 ( 세부구현은 숨김 )
- 비동기 통신 : 요청에 대한 응답과 관계없이 처리 ↔ 동기 : 요청에 대한 응답이 이루어지기까지 대기
- 서비스별로 데이터베이스 분리 : 독립적인 저장소 → 하나의 데이터베이스에 오류가 발생해도 사용가능
- 회로차단( Circuit Break ) : 서비스가 서비스를 호출 / 하나의 서비스에서 문제가 발생해도 접근, 호출하지 않으면 다른 서비스에 영향이 가지 않음( 전이되지 않음 ) domino effect를 방지
(2) High Cohesion ( 높은 응집력 )
- 단일책임원칙(SRP : Single Responsibility Principle) : 변경은 작은단위(하나의 서비스, 코드베이스)에서 진행
- 관련 디자인패턴 : Strategy pattern, Factory pattern, Adapter pattern
- Domain-Driven Design : 업무를 작은 도메인으로 구별
* Loosely Coupled는 서비스간의 관계를 말하고 High Cohesion는 서비스 내부의 관계를 말한다.*
(3) Bounded Context(도메인 경계)
하나의 큰 서비스 내부에서 기능별, 서비스별로 쪼갬 = 경계가 있는 컨텍스트
Rest API를 이용하여 통신 : 유의미한 기능을 open, 상세분석 및 내부조작을 close
서비스 크기에 따른 아키텍처 비교
- Monolith : 코드베이스 하나
- Modular monolith : 코드베이스 하나, 기능별로 폴더 구분
- Mini Service : 코드베이스가 서로다름
- Micro Service : 가장 작게 구분
→ 실무에서는 micro service보다 mini service 정도가 더욱 효율적임, 적절함
→ 업무요건, 요청, 기능이 수시로 바뀌는 경우 + 첫시작인 경우 micro service가 더욱 비효율적임을 명심하라
→ 마이크로 서비스는 빠른 서비스 배포, 소비자에 민감한 애플리케이션에 적합
마이크로서비스의 핵심은 서비스 단위에서의 독립적인(개별적인) 빌드, 배포이다. ⇒ 소비자의 개별적인 요구사항, 기능을 빠르게 구현할 수 있음
- 전체 빌드(Build) 가 아닌 서비스 단위의 빌드 및 배포
- 테스트 코드 또는 TDD 필요
- 컨테이너 환경에 매우 적합
실습환경 구축
docker compose를 이용하여 IDE 컨테이너 생성 → 이를 통해 로컬 쿠버네티스 접속
(1) IMAGE : rudalsss/myide
# <https://hub.docker.com/r/linuxserver/code-server>
FROM linuxserver/code-server:4.93.1
# ENV for Code-server (VSCode)
ENV TZ="Asia/Seoul"
ENV PUID=0
ENV PGID=0
# Make DIR for code-server
RUN mkdir /code && chown 1000:1000 /code
# Update & Install the packages
RUN apt-get update && apt-get -y upgrade
RUN apt-get install -y ca-certificates curl gnupg software-properties-common wget unzip apt-transport-https telnet net-tools vim iputils-ping openjdk-11-jdk python3 python3-pip gh
# Install Jupyter
RUN pip install --no-cache-dir --break-system-packages jupyter ipykernel
# ENV for JDK
ENV JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64"
ENV PATH="${JAVA_HOME}/bin:${PATH}"
# Docker CLI
RUN apt-get update && install -m 0755 -d /etc/apt/keyrings \\
&& curl -fsSL <https://download.docker.com/linux/ubuntu/gpg> -o /etc/apt/keyrings/docker.asc \\
&& chmod a+r /etc/apt/keyrings/docker.asc
RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] <https://download.docker.com/linux/ubuntu> \\
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \\
tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt-get update && apt-get install -y docker-ce docker-ce-cli
# Install AWS CLI from `amazon/aws-cli` image
COPY --from=amazon/aws-cli /usr/local/aws-cli/v2 /usr/local/aws-cli/v2
RUN ln -s /usr/local/aws-cli/v2/current/bin/aws /usr/local/bin/aws
RUN ln -s /usr/local/aws-cli/v2/current/bin/aws_completer /usr/local/bin/aws_completer
# Terraform
RUN wget -O- <https://apt.releases.hashicorp.com/gpg> | gpg --dearmor | tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null \\
&& gpg --no-default-keyring --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg --fingerprint \\
&& echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] <https://apt.releases.hashicorp.com> $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list
# RUN apt update && apt-get install -y terraform=1.9.7
# RUN apt update && apt-get install -y terraform
RUN apt update && apt-get install -y terraform
# Kubectl
RUN curl -fsSL <https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key> | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg \\
&& echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] <https://pkgs.k8s.io/core:/stable:/v1.29/deb/> /' | tee /etc/apt/sources.list.d/kubernetes.list
RUN apt-get update && apt-get install -y kubectl
# Kubectx & Kubens
RUN git clone <https://github.com/ahmetb/kubectx> /opt/kubectx \\
&& ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx \\
&& ln -s /opt/kubectx/kubens /usr/local/bin/kubens
docker build -t rudalsss/myide .
docker login —user rudalsss
docker push rudalsss/myide
이미지 빌드해서 Dockerhub에 올려둔다.
Docker CLI, AWS CLI, Kubectl, Kubectx & Kubens, Terraform이 설치된 리눅스 code-server( VSCode환경 )
기존에는 시스템에서 필요한 util들을 직접 설치 ⇒ docker의 혁신 : 설치없이 선언으로 설치효과, binary를 받아와서 자동으로 만들어줌
[ 선언설치의 효과 ]
- 이식성 : 다른 환경에서도 사용가능
- git ops : 선언은 단순문자(코드) → 관리 및 수정 유지가 용이함
- 자동화 : 선언만 해두면 git 엔진에서 설치를 자동적으로 수행
- 추상화
[ Quiz ]
도커파일에서 명령어 1줄은 1개의 이미지 레이어이다. → TRUE
&&으로 연결시키면 모두 1줄이 된다.
레이어마다 고유한 일정길이의 hash값을 가지고 식별됨( 해시알고리즘 : input값이 조금이라도 다르면 상이한 값이 나옴 → 변경을 쉽게 파악할 수 있음 )
캐시의 이용 : 이미지 변경 및 수정시 고정된 부분은 이전의 레이어를 재사용하고 변경된 부분만 반영 → 네트워크 트래픽을 감소시키는 효과!
컨테이너 내부의 특정 파일에 접근하여 수정 및 생성이 가능하다 → TRUE
그러나 컨테이너가 종료되면 그 내용은 휘발됨
컨테이너는 union file system, overlay filesystem을 사용한다.
- union filesystem : 파일 위에 새로운 파일이 올라가면 위에 있는 파일이 우선한다.
- 컨테이너를 띄우면(이미지의 컨테이너화) 기존의 이미지의 read only 레이어(immutable) 외에 read write 레이어( container layer )가 생성됨 ( 오버레이 파일시스템 으로 r/w레이어가 우선함 )
- r/w레이어는 호스트의 디스크( var/lib/container )에 존재함 → 호스트의 리소스를 같이 먹기 때문에 위험함
(2) Container : ide
version: "3.8"
name: "aws-cicd-practice"
services:
# jenkins:
# image: jenkins/jenkins:lts
# container_name: jenkins
# user: root
# ports:
# - "8081:8080" # Jenkins UI 포트
# - "50000:50000" # 에이전트 연결 포트
# volumes:
# - jenkins-home:/var/jenkins_home # Jenkins 데이터를 영구적으로 저장
# - /var/run/docker.sock:/var/run/docker.sock # Docker를 Jenkins에서 사용 가능하게 설정
# environment:
# - JAVA_OPTS=-Djenkins.install.runSetupWizard=false # 초기 설정 마법사 비활성화 옵션
server:
image: dangtong76/myide
container_name: "ide"
networks:
- kind_network
environment:
FILE__PASSWORD: /run/secrets/code-server-password
env_file:
- .env
working_dir: /code
ports:
- "8444:8443"
- "5500:5500"
secrets:
- code-server-password
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- cloud-cicd-src:/code/cloud-cicd-src
- vscode:/config
networks:
kind_network:
name: kind
external: true
volumes:
cloud-cicd-src:
external: true
name: cloud-cicd-src
vscode:
external: true
name: vscode
# jenkins-home:
# external: true
# name: jenkins-home
secrets:
code-server-password:
file: password.txt
컨테이너의 휘발성으로 인해 호스트의 디렉토리와 바인드하여 그 내용을 저장한다. ⇒ volume
IDE 컨테이너에서는 소스코드 및 extension 설치를 위한 영역을 볼륨에 저장
docker volume create --opt device="C:\\Users\\KHP\\Documents\\cloudwave\\k8s-practice\\cloud-cicd\\makeENV\\src" --opt o=bind --opt type=none cloud-cicd-src
docker volume create --opt device="C:\\Users\\KHP\\Documents\\cloudwave\\k8s-practice\\cloud-cicd\\makeENV\\vscode" --opt o=bind --opt type=none vscode
도커볼륨을 cloud-cicd-src, vscode라는 alias로 구축해둔다 ( 논리적인 외부볼륨 = external ) ⇒ 각각 윈도우 환경에서 ./src, ./vscode에 바인딩됨
볼륨 연결시 컨테이너 레이어, 이미지 레이어에 별도인 독립적인 영역이 사용되는 것
(3) Cluster : cwave-cluster
[ 클러스터 정의 yaml 작성 ]
**kind: Cluster**
apiVersion: kind.x-k8s.io/v1alpha4
name: cwave-cluster
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
image: kindest/node:v1.29.4
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker
image: kindest/node:v1.29.4
- role: worker
image: kindest/node:v1.29.4
networking:
serviceSubnet: "10.120.0.0/16"
podSubnet: "10.110.0.0/16"
- kind: Cluster → 클러스터 리소스를 생성하는 것을 선언
- 쿠버네티스 버전
- 쿠버네티스 : k8s
- 쿠버네티스 경량화 버전 : k3s
- kindest/node:v1.29.4 : Kind (Kubernetes in Docker)에서 사용되는 기본 노드 이미지
- 가상의 서비스 컨테이너(nodes) → 역할(role)로 구분 ( contol-plane, worker )
- contorl node : 쿠버네티스의 머리에 해당 → 조종 및 제어
- worker node : 어플리케이션이 수행되는 노드
[ kind 설치 ]
kind (Kubernetes IN Docker) : Docker 컨테이너 위에서 실행되는 경량 쿠버네티스 클러스터를 생성하기 위한 도구
- Kubeadm: 대규모, 프로덕션용 클러스터를 만들 때 사용.
- Kind: 로컬 환경에서 간단한 클러스터를 만들 때 사용.
먼저 chocolatey설치
chocolatey : 윈도우 운영 체제의 패키지 관리 시스템으로 소프트웨어 설치, 업그레이드, 구성, 삭제 등을 명령어 기반으로 자동화
choco install kind
kind 설치
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('<https://community.chocolatey.org/install.ps1>'))
이때 kind 실행파일은 올라가지 않도록 .gitignore에 추가
kind-windows-amd64
kind-windows-amd64.exe
+) 파일로 다운받는 경우
사용자 환경변수 및 시스템 환경변수의 Path C:\\Users\\KHP\\Documents\\cloudwave\\k8s-practice\\cloud-cicd\\makeENV→ 다운로드 실행파일이 위치한 해당 경로를 추가함
kind 명령어를 어디에서나 즉각적으로 실행가능
[ kind를 이용한 클러스터 생성 ]
kind create cluster —config 3-node-k8s.yaml
kind를 이용 + 요청양식을 yaml로 작성하면 이에 맞게 제작
kind get clusters # 생성한 클러스터 조회
kubectl get no # 생성한 노드 조회
kubectl : 쿠버네티스 클러스터를 관리하기 위한 CLI(Command-Line Interface) 도구, kind설치시 자동으로 설치됨
네트워크 조회 → kind라는 이름의 도커 네트워크가 자동적으로 생성됨
kind는 Docker 컨테이너 기반으로 클러스터를 생성 → 클러스터별로 새로운 Docker 네트워크가 생성
[ IDE 컨테이너 네트워크 재설정 ]
docker-compose.yaml( IDE컨테이너를 담고 있는 aws-cicd-practice 프로젝트를 정의 )에서 네트워크 설정을 다시 진행( kind네트워크와 묶음 ) 후에 docker compose up -d를 진행(업데이트) ⇒ kind라는 이름의 external 네트워크를 서비스에 적용( 클러스터의 노드들과 같은 네트워크 대역을 사용가능 )
...
services:
server:
image: rudalsss/myide
container_name: "ide"
networks:
- kind_network
....
networks:
kind_network:
name: kind
external: true
[ 컨테이너의 구축상황 ]
- aws-cicd-practice compose
IDE container ⇒ 2개의 파일을 물고 있음( /src, /config )
- cwave 클러스터( k8s )
- control plane 1개
- worker node 2개
이 컨테이너들(4개)은 모두 kind network( 172.19.0.0/16 )로 묶여있음 → 상호통신가능
docker inspect network kind
k8s를 만들면서 kind network가 자동으로 생성되었고 이를 IDE에 연결함
IDE내부에 kubectl를 깔아서 → 클러스터의 contorl plane과 통신이 가능함
[ kind ]
- 쿠버네티스 클러스터(cwave-cluster)를 구축하면서 이에 접근제어할 수 있는 tool인 kubectl을 자동적으로 설치함
- 호스트(윈도우)에서 생성한 클러스터 → C:\Users\KHP\.kube의 config에 접속정보 & 인증서를 저장 ( 홈디렉토리/.서비스의 config파일에 접속정보가 저장됨 )
이렇게 host의 kube에는 인증정보 및 기록이 남아있지만 IDE 컨테이너 내에는 해당 기록이 없음 → 윈도우에서 인증정보를 받아와서 넣어주어야(복붙) IDE컨테이너에서도 접속이 가능함
kind get kubeconfig --name cwave-cluster | CLIP
표준출력이 클립보드로 복사된다.
IDE에서 기존에 바인드된 파일 /config( 볼륨 vscode에 바인딩 )를 가시적으로 생성하고 여기에 하위경로 .kube/config 를 생성 & config내용을 복붙하여 넣어줌
이때 cluster의 서버주소는 local host의 포트가 아니라 control plane의 ip와 외부에 연결된 포트 6443으로 접속 ( https://172.19.0.4:6443 ) control plane의 API서버 주소로 바꾸는 작업임
- IDE에서도 정상적으로 쿠버네티스 클러스터에 접속이 가능해짐
[ Kubectl 기본 사용법 ]
- kubectl 리소스 : 리소스를 제어하기 위한 문법
- kubectl get all : 모든 리소스에 대한 조회
- kubectl get po, svc, ns
- kubectl config get-contexts
- context : API서버정보, 인증서를 기반으로 context를 생성 가르키는 지시자 → 전환가능( switch를 전제함 ) 클러스터 여러개 생성가능, 클러스터의 숫자만큼 정해짐
- .kube/config하에는 cluster와 context 정보가 존재함
- cluster : 여러 개의 노드들로 구성된 Kubernetes 환경
- API server : master node에 접속할 수 있는 API server의 정보 → 바꿔서 접속가능
- context : 클러스터, 사용자, 네임스페이스 등과 관련된 환경 설정을 하나로 묶은 것
- current-context : 현재 활성화된 context
- user : Kubernetes 클러스터에 접근할 때 사용할 사용자 정보 → 토큰, 인증서 등을 포함
- 인증서 : ID/PASSWORD가 아닌 인증서 기반으로 접속
- 나의 개인키(개인인증서)
- CA 인증서
- context : API서버정보, 인증서를 기반으로 context를 생성 가르키는 지시자 → 전환가능( switch를 전제함 ) 클러스터 여러개 생성가능, 클러스터의 숫자만큼 정해짐