쿠버네티스란

쿠버네티스란 컨테이너 오케스트레이션 도구입니다. 간단히 말해, 여러 컨테이너를 관리하는 도구입니다. 앞서 도커 컴포즈에 관한 글에서 도커 컴포즈와 쿠버네티스를 간단히 비교한 적이 있습니다. 도커 컴포즈는 여러 컨테이너 생성 및 폐기가 가능하지만, 관리 기능은 없다고 하였습니다. 반면 쿠버네티스에는 관리 기능이 있죠. 뿐만 아니라 쿠버네티스는 동일 구성의 컨테이너 여러 세트를 생성하는 것에도 적합한데, 이 부분에서 쿠버네티스의 컨테이너 관리 기능 부각되는 게 아닐까 싶습니다. 만약 여러 컨테이너를 다루는 데 관리 기능이 없다면? 그랬다면, 엔지니어가 일일이 컨테이너 상태를 모니터링하며 장애가 발생할 때마다 컨테이너를 버리고 만들어주는 일을 해줘야만 했을 겁니다. 하지만 쿠버네티스는 바로 이 컨테이너 관리를 해주는 도구인 것이죠.

그럼 여러 컨테이너를 생성하고 또 관리하는 기능은 어떻게 제공되는 걸까요? 바로 이 작동 원리를 이해하기 위해선 먼저 쿠버네티스 구조를 이해할 필요가 있습니다.

 

 

쿠버네티스 구조

쿠버네티스는 여러 컨테이너를 관리할 수 있는 오케스트레이션 도구입니다. 따라서 이를 활용해 컨테이너 그룹을 배포할 수 있는데요. 중요한 건 쿠버네티스는 컨테이너 그룹을 포함해 클러스터라는 것을 만들어낼 수 있다는 점입니다.

클러스터란 컨트롤 플레인과 데이터 플레인으로 구성된 하나의 쿠버네티스 시스템을 의미합니다. 

 

왜 클러스터를 배포할까요? 만약 컨테이너만 배포한다면 어땠을까요?

그럼 쿠버네티스는 오케스트레이션 도구라 불릴 수 없었을 것입니다. 이점에서 쿠버네티스에는 관리를 위한 구성요소가 있어야 한다는 걸 생각해볼 수 있습니다. 이 관리를 담당하는 레이어가 컨트롤 플레인이고 컨테이너를 띄우고 서로 연결될 수 있도록, 일명 실무자와 같은 역할을 수행하는 레이어가 데이터 플레인입니다.

 


출처

 

쿠버네티스 컴포넌트

쿠버네티스 클러스터는 컴퓨터 집합인 노드 컴포넌트와 컨트롤 플레인 컴포넌트로 구성된다.

kubernetes.io

 

용어집

 

kubernetes.io

 

 

 

도커 컴포즈 개념

도커 컴포즈란 파일 하나로 여러 컨테이너를 생성하고 폐기할 수 있도록 하는 도구입니다.

만약 도커 컴포즈가 없다면, 일일이 커맨드를 입력해야 하는데 이를 한번에 해결해주는 도구이죠.

 


도커 컴포즈 vs Docker file, Kubernetes

Dockerfile 스크립트는 이미지 만드는 용도입니다. 네트워크나 볼륨을 생성할 수 없습니다.

그러나 도커 컴포즈 파일은 컨테이너를 비롯한 네트워크나 볼륨 등 주변 환경까지 포괄합니다.

앞서 말씀드렸듯, 여러 커맨드를 입력할 필요 없이 파일 하나로 해결해낼 수 있는 것입니다.

Kubernetes는 여러 컨테이너를 관리하는 도구입니다. 따라서 생성 및 폐기를 비롯한 관리 기능이 제공됩니다.

그러나 도커 컴포즈에는 컨테이너 관리 기능이 없습니다.

 


도커 컴포즈 사용 및 작동 원리

도커 컴포즈는 도커 엔진과 사용법이 대동소이합니다. 그러나 엄연히 별개의 소프트웨어입니다. 따라서 별도 설치가 필요합니다. 다만 리눅스 환경에서만 설치가 필요할 뿐, 윈도우나 MAC OS에선 필요치 않습니다. 이유는 Docker Desktop 설치 시 함께 설치되기 때문입니다.

도커 컴포즈의 파일 형식은 YAML 파일 형식으로, "파일이름.yml" 양식을 따릅니다.

파일은 호스트에 위치하며 도커 컴포즈가 이를 읽고 대신 커맨드를 입력해주는 방식으로 작동합니다. 단, 파일은 폴더에 하나만 있어야 합니다. 만약 여러 YAML 파일이 있다면 폴더를 각각 분리해야 합니다.

 


도커 컴포즈 커맨드

YAML 파일 커맨드 주요 커맨드로는 up, down이 있습니다.

도커 컴포즈 주요 커맨드: UP

up은 YAML 파일을 읽는 명령어입니다.

docker-compose -f C:\Users\user\Desktop\study\cloud\redmine-maria\docker-compose-red-maria.yml up

up 명령어 사용 시 주의해야할 점 2가지가 있습니다. 먼저, up 명령어는 YAML 파일을 한번 읽고 나면 끝입니다. 따라서 up 실행 이후 YAML 파일을 수정하더라도 동기화되진 않습니다. 마찬가지로, YAML 파일로 생성된 컨테이너의 설정을 변경하더라도 YAML 파일에 반영되지 않습니다. 다음으로, 도커 엔진에 생성되는 컨테이너 이름은 도커 컴포즈에 명시한 service 이름과 다르다는 점입니다. 도커 엔진에 생성되는 컨테이너 이름은 "leaf 폴더명_service에 명시한 컨테이너 이름_번호"로 생성됩니다. 예를 들어, C:\Users\user\Desktop\study\cloud\wordpress-maria\docker-compose-red-maria.yml에 대해 up 커맨드를 입력한 경우 생성되는 컨테이너 이름은 "wordpress-maria-${services에 명시한 컨테이너 이름}-1" 입니다.

번호는 YAML 파일이 여러 번 실행되면, 즉 같은 구성의 컨테이너 세트가 여러 개 생성되면 넘버링 형태로 붙습니다. 

docker-compose -f C:\Users\user\Desktop\study\cloud\redmine-maria\docker-compose-red-maria.yml up --scale maria_lim=2

*근데 여러 컨테이너를 만드는 도커 컴포즈에서 의존 관계와 맞지 않게 특정 컨테이너만 여러 개 생성하면, 장애가 날 가능성이 높습니다. 여러 컨테이너가 포트번호를 공유하는 것(포트 번호 중복)도 장애를 야기할 수 있습니다. 따라서 여러 세트의 컨테이너를 생성하는 경우 쿠버네티스 활용을 권장합니다.

 

도커 컴포즈 주요 커맨드: DOWN

down은 YAML로 실행된 컨테이너, 네트워크를 폐기하는 명령어입니다.

down 명령어에서 중요한 건 image와 volume은 삭제되지 않는다는 점입니다. 따라서 별도 폐기 작업이 필요합니다.

docker-compose -f C:\Users\user\Desktop\study\cloud\redmine-maria\docker-compose-red-maria.yml down

 

 


도커 컴포즈 파일 양식 및 예제

양식

version: "${버전}"

services:
  ${컨테이너 이름}:
    depend_on:
      - ${의존 컨테이너 이름}
    image: ${이미지 이름}
    networks:
      - ${네트워크 이름}
    ports:
      - ${클라이언트 요청하는 포트}:${리다이렉트되는 포트}
    restart: ${컨테이너 재시작 여부}
    #restart 설정 값: no, always, on-failure, unless-stopped
    environment:
      ${환경변수 이름}=${환경변수 값}

networks:
  ${네트워크 이름}:

volumes:
  ${볼륨 이름}:

 


mysql+wordpress

version: "3"

services:
  mysql000ex11:
    image: mysql
    networks:
      - wordpress000net1
    volumes:
      - mysql000vol11:/var/lib/mysql
    restart: always
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: myrootpass
      MYSQL_DATABASE: wordpress000db
      MYSQL_USER: wordpress000kun
      MYSQL_PASSWORD: wkunpass
  wordpress000ex12:
    depends_on:
      - mysql000ex11
    image: wordpress
    networks:
      - wordpress000net1
    volumes:
      - wordpress000vol12:/var/www/html
    ports:
      - 8085:80
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpass
      MYSQL_DATABASE: wordpress000db
      MYSQL_USER: wordpress000kun
      MYSQL_PASSWORD: wkunpass

networks:
  wordpress000net1:

volumes:
  mysql000vol11:
  wordpress000vol12:

 

 

 


mysql+redmine

version: "1"

services:
  cloudlim_mysql:
    image: mysql
    networks:
      - cloudlim_net
    volumes:
      - cloudlim_vol1:/var/lib/mysql
    restart: always
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: myrootpass
      MYSQL_DATABASE: cloudlimdatabase
      MYSQL_USER: cloudlim
      MYSQL_PASSWORD: limlim1234
  cloudlim_redmine:
    depends_on:
      - cloudlim_mysql
    image: redmine
    networks:
      - cloudlim_net
    volumes:
      - cloudlim_vol2:/usr/src/redmine/files
    ports:
      - 8086:3000
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpass
      MYSQL_DATABASE: cloudlimdatabase
      MYSQL_USER: cloudlim
      MYSQL_PASSWORD: limlim1234

networks:
  cloudlim_net:

volumes:
  cloudlim_vol1:
  cloudlim_vol2:


 

mariadb+redmine

version: "2"

services:
  maria_lim:
    image: mariadb
    networks:
      - net_lim
    volumes:
      - vol_lim1:/var/lib/mysql
    restart: always
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: mariarootpw
      MYSQL_DATABASE: limdb
      MYSQL_USER: cloudlim
      MYSQL_PASSWORD: lim1234
  cloudlim_redmine:
    depends_on:
      - maria_lim
    image: redmine
    networks:
      - net_lim
    volumes:
      - vol_lim2:/usr/src/redmine/files
    ports:
      - 8087:3000
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: mariarootpw
      MYSQL_DATABASE: limdb
      MYSQL_USER: cloudlim
      MYSQL_PASSWORD: lim1234

networks:
  net_lim:

volumes:
  vol_lim1:
  vol_lim2:

 


 

출처

 

그림과 실습으로 배우는 도커 & 쿠버네티스 - 예스24

컨테이너나 도커를 도통 이해하기 어려운 분들을 위한 본격 도커 입문서!이 책은 컨테이너 기술이 어렵게 느껴지는 엔지니어나 백엔드 기술에 자신이 없는 분들을 위한 도커 입문서다. 자세한

www.yes24.com

 

 

1. Desktop에서 Docker Hub 로그인 및 리포지토리 생성

도커허브는 도커가 운영하는 공식 리지스트리이다.

이곳에서 개인이 리포지토리를 생성할 수 있다.

 

 

2.Dockerfile 생성

 

3. 도커 엔진에 이미지 업로드

docker build cloudlim C:\Users\user\Desktop\study\cloud

 

*t 옵션을 사용해 "계정명/리포지토리명:버전" 으로 빌드하면 바로 도커 허브로 업로드(push) 가능하다

*빌드는 됐는데 파이프라인에 문제 있는 것 같다는 메시지가 출력될 수도 있다. 그럴 땐 도커 엔진을 껐다 키면 해결된다.

 

4. 태그 생성

docker tag cloudlim lim0517sh/cloudlim:1

docker tag 명령어 입력 시, 해당 이미지에 태그가 달리는 것이 아닌 태그 달린 이미지가 생성되는 것이다.

docker images 또는 docker image ls로 확인해볼 수 있다.

 

5.  도커 허브 로그인

docker login

 

6. 도커 엔진 이미지를 도커 허브 리포지토리에 업로드

docker push lim0517sh/cloudlim:1

"계정명/리포지토리이름:버전" 양식으로 업로드하면 된다.

 

7. 도커 허브 확인

 

8. 도커 허브 이미지 다운로드

docker pull lim0517sh/cloudlim:1

"계정명/리포지토리명:버전" 양식으로 이미지를 pull한다.

04-3 명령어 사이클과 인터럽트
CPU가 메모리의 명령어를 실행하는 데는 정해진 패턴, 흐름이 있다. 이 흐름 또는 주기를 명령어 사이클이라고 한다.
근데 간혹 이 정해진 흐름을 끊기도 하는데, 이 흐름을 끊는 신호를 인터럽트라고 함.

명령어사이클: 인출>실행>인출>실행>인출..반복
1. 인출 사이클: 가장 먼저 메모리에 있는 값을 CPU로 가져와야한다. 이를 인출이라 함
2. 실행 사이클: CPU에 가져온 값을 실행함
근데 인출 이후 메모리 접근이 더 필요한 경우가 있다(오퍼랜드는 주소필드라고도 불린다는 점!) → 1.5 간접사이클

1. 인출 사이클

1.5 간접 사이클

2. 실행 사이클


인터럽트: CPU가 꼭 주목 또는 먼저 처리해야할 다른 일이 생겼을 때
- 인터럽트 종류: 동기 인터럽트(예외), 비동기 인터럽트(하드웨어 인터럽트)

동기인터럽트(exception)
- CPU가 예기치 못한 상황을 접했을 때 발생
- 예) 메모리 갔더만 원하는 데이터가 없거나 실행할 수 있는 명령어가 없거나 디버깅..등

비동기 인터럽트: 주로 입출력장치에 의해 발생
- 알림 같은 거임
ㄴ 예1) 프린터가 CPU에게 "나 프린트 다했어!"
ㄴ 예2) 키보드가 CPU에게 "타이핑 발생했어!"
- 왜 있는거임?? 일반적으로 입출력 장치의 입출력 작업은 CPU에 비해 느림 → (인터럽트 없다면)cpu가 입출력 작업 완료 여부 확인을 주기적으로 해줘야함...그래서 인터럽트 둬서 CPU가 굳이 계속 확인할 필요 없도록 하기 위해 인터럽트 사용

인터럽트 처리 순서 (=인터럽트 서비스루틴을 실행하고 본래 수행하던 작업으로 다시 돌아오는 과정+그리고 인터럽트 시작 주소는 인터럽트 벡터를 통해 알 수 있다)
1. 입출력장치 > CPU 인터럽트 요청 신호 발송: 입출력장치가 cpu에게 말한다 "지금 끼어들어도 됨?"
2. CPU가 실행 사이클 끝내고 명령어 인출 전 항상 인터럽트 여부 확인.
3. CPU가 인터럽트 요청 확인 후 인터럽트 플래그를 통해 현재 인터럽트를 받을 수 있는지 확인
ㄴ플래그 레지스터에서 인터럽트 받아들일 수 있는지 확인하는 값. 이걸로 CPU가 이렇게 얘기할 수 있는거임 "지금은 안되요~장사 안해요~"
ㄴ 근데 모든 인터럽트를 인터럽트 플래그로 막을 수 있는 건 아님. 긴급한 건이라면 이 플래그값 상관없이 인터럽트 들어가기도 함(Non Maskable Interupt)
4. 인터럽트 받아들일 수 있다면 CPU는 지금까지 작업 백업
5. CPU는 인터럽트 벡터(인터럽트를 구분하기 위한 정보) 참조해 인터럽트 서비스 루틴 실행
ㄴ 인터럽트 서비스 루틴마다 메모리에서 차지하는 주소가 달라..그니깐 인터럽트 벡터 값을 통해 CPU가 인터럽트 서비스루틴을 메모리의 어디서부터 시작하면 되는지 알 수 있음
6. 인터럽트 서비스 루틴(메모리 안에서 실행되는 프로그램) 끝나면 (4)에서 백업해 둔 작업 복구 후 실행 재개
ㄴ 인터럽트 서비스 루틴은 인터럽트가 발생했을 때 어떻게 처리하면 좋을지 적혀있는 프로그램이라 생각하면 됨(like "키보드 타이핑에는 이렇게 행동하세요")
ㄴ 근데 어떻게 복구함? 기존에 레지스터에 있던 값들을 어디 보관? → 지금까지 작업내용은 stack(메모리 내 스택 영역)에 백업해놓음.

 

 


출처

 

 

 



컨테이너는 데이터와 프로그램을 독립 실행할 수 있는 공간

그래서 컨테이너끼리 통신하려면 네트워크 구축 필요

→ 네트워크 구축 후 mysql과 wordpress 컨테이너 배포

docker network create wordpress000net1

docker run --name mysql000ex11 -dit --net=wordpress000net1 -e MYSQL_ROOT_PASSWORD=myrootpass -e MYSQL_DATABASE=wordpress000db -e MYSQL_USER=wordpress000kun -e MYSQL_PASSWORD=wkunpass mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password

docker run --name wordpress000ex12 -dit --net=wordpress000net1 -p 8085:80 -e WORDPRESS_DB_HOST=mysql000ex11 -e WORDPRESS_DB_NAME=wordpress000db -e WORDPRESS_DB_USER=wordpress000kun -e WORDPRESS_DB_PASSWORD=wkunpass wordpress

 

그리곤 브라우저를 통해 localhost:8085로 접속했으나 에러 발생

에러 메시지 "Error establishing a database connection"

 

컨테이너 상태 봤더니 mysql 상태가 exited

 

mysql 컨테이너 로그 확인(docker logs mysql000ex11)했더니 인식 안되는 환경변수(default-authentication-plugin)가 있음

 

그래서 걔 빼고 입력해봄

docker network create wordpress000net1

docker run --name mysql000ex11 -dit --net=wordpress000net1 -e MYSQL_ROOT_PASSWORD=myrootpass -e MYSQL_DATABASE=wordpress000db -e MYSQL_USER=wordpress000kun -e MYSQL_PASSWORD=wkunpass mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

docker run --name wordpress000ex12 -dit --net=wordpress000net1 -p 8085:80 -e WORDPRESS_DB_HOST=mysql000ex11 -e WORDPRESS_DB_NAME=wordpress000db -e WORDPRESS_DB_USER=wordpress000kun -e WORDPRESS_DB_PASSWORD=wkunpass wordpress

 

브라우저에서 워드프레스 정상 출력 확인

Docker Desktop 설치 후 실습 진행

 

명령어 구조: docker + 커맨드(상위 커맨드 + 하위 커맨드) + 대상

근데 상위 커맨드는 종종 빼고 입력해도 됨(왜? 역사적인 이유로..걍 쓰다보니 그게 편해서 라는 거인듯)


Docker 설치 확인

 


기본실습1) 아파치 설치된 이미지 배포해보기

옵션 설명

- "--name" : 다음 나오는 정보가 컨테이너 이름입니다.

- "-d" : 백그라운드로 실행해주세여(daemon의 약자인듯)

- httpd: 이미지 이름

 

컨테이너 확인

- docker ps 또는 docker container ls

- STATUS가 UP=실행중 / Exited=정지됨

 

컨테이너 정지

 

컨테이너 전체 리스트 확인

 

컨테이너 없앰(없애면 리스트에서도 안보임)

 

 


기본실습2) 

옵션 설명

- "-p 8080:80" : 포트는 8080으로 접근하면 컨테이너 80 포트에 도달하도록 해주세여(호스트 포트 8080: 컨테이너 포트 80)

 

→ 그래서 localhost:8080으로 접근해보면

 

 

 

 

컨테이너, 도커 기본 개념

  • 컨테이너? 데이터나 프로그램을 격리시키는 조립형 창고
    • 컨테이너는 자유롭게 옮길 수 있다(도커 엔진A → 도커 엔진B: easy)
  • 이런 컨테이너를 다루는 기술이 Docker
    • (주로) 서버에서 사용되는 소프트웨어
    • Docker 제약사항: 리눅스
  • 어떤 컨테이너를 만들건데? 이걸 정하는 게 바로 이미지
  • 근데 왜 필요함?
    • 프로그램을 동작시키려면 이걸 실행시킬 실행 환경(런타임)이 필요함.
    • 그뿐만 아니라 라이브러리들도 런타임마다 제각각임.
    • 또 어떤 프로그램끼리는 같은 디렉토리를 공유할 수도 있음. 프로그램 여러 개를 동시에 가동시키는 데 디렉토리를 공유하고 있었다..? 그건 재앙..

가상화 기술 vs 도커

  • 가상화 기술은 가상의 물리 서버 → 실질적으로 하나의 물리 서버나 마찬가지.
  • 도커는 운영체제 일부 기능을 호스트 컴퓨터(물리 서버)에 의존

도커 동작 원리

  • 물리서버의 리눅스 운영체제 위에, 도커 엔진 위에, 컨테이너.
  • 이 컨테이너 안에는 위에서 설명한 프로그램이나 데이터가 위치하고 또 리눅스 운영체제 비스무리한 게 위치한다.
    • 비스무리? 원래 운영체제는 커널+주변 영역으로 구성됨
      • 커널: 하드웨어 다루는 애 / 주변 영역: 프로그램의 내용을 커널에 전달하는 애
      • 컨테이너에는 주변 영역만 들어 있음. 원래 컨테이너는 개별 공간 마냥 분리되어 있는데 그럼 하드웨어 장비를 어떻게 써..그래서 주변 영역이 소통 창고 같은 느낌으로 있는 거임.
      • 컨테이너 속 프로그램의 작업 → 컨테이너 속 리눅스 OS 주변 영역이 의견 수렴 후 전달 → 도커 엔진이 컨테이너들의 의견 수렴 후 전달 → 커널 수렴
    • 컨테이너에는 주변 영역만 있기 때문에 이 덕분에 도커는 “가벼움”

도커 이미지

  • 이미지는 컨테이너를 만드는 빵틀 같은 거임. 그래서 똑같은 컨테이너 여러 개 찍어내듯 만들어낼 수 있음
  • 근데 빵틀과 달리 개조하기 겁나 쉬움
  • 다른 도커 엔진으로 공유하는 것도 쉬움
  • 아예 공유하라고 만들어 놓은 곳이 도커 허브임(hub.docker.com)

도커 생애주기

  • 도커는 사실 일회용품 같은 거임.
    • 설치된 소프트웨어 업데이트 필요하면 일일이 해주는 게 아니라, 걔네들 설치된 거 다 폐기 시키고 그냥 새로운 버전이 설치된 이미지로 컨테이너 쫙~ 뽑아서 쓰는 거임
  • 근데, 그럼 그 안에 있는 데이터는 우짬? 그래서 데이터는 도커 설치된 물리 서버의 디스크에 마운트해 따로 저장하긴 함. 이러면 컨테이너 간 데이터 공유도 편함.

 

 

 


출처: 

 
그림과 실습으로 배우는 도커 & 쿠버네티스
이 책은 컨테이너 기술이 어렵게 느껴지는 엔지니어나 백엔드 기술에 자신이 없는 분들을 위한 도커 입문서입니다. 자세한 그림과 친절한 실습을 통해 리눅스 지식이나 서버 구축 경험이 없어도 컨테이너와 도커, 쿠버네티스에 대한 지식을 쉽게 이해할 수 있습니다. 도커의 개념부터 동작 방식, 명령어 사용법, 컨테이너 운용, 나아가 도커 컴포즈와 쿠버네티스까지, 컨테이너 기술에 대한 배경지식이 전혀 없는 분들도 도커와 쿠버네티스의 개념과 기초 사용법을 익힐 수 있도록 안내합니다. 도커나 쿠버네티스를 배우고 싶은 초보자라면 철저하게 입문자의 눈높이에 맞춘 이 책으로 도커의 세계에 첫발을 내디뎌 보세요.
저자
오가사와라 시게타카
출판
위키북스
출판일
2022.04.05

 

 

 

3 Tier Architecture

3 Tier Architecture 개념

애플리케이션을 프레젠테이션 계층 또는 사용자 인터페이스, 데이터가 처리되는 애플리케이션 계층 그리고 애플리케이션과 관련된 데이터가 저장 및 관리되는 데이터 계층이라는 3개의 논리적이고 물리적인 컴퓨팅 계층으로 구성하는 확립된 소프트웨어 애플리케이션 아키텍처 각 계층이 자체 인프라에서 실행되기 때문에 각 계층이 별도의 개발 팀에 의해 동시에 개발될 수 있으며 다른 계층에 영향을 주지 않고 필요에 따라 업데이트되거나 확장될 수 있음

출처: IBM "3계층 아키텍처란?"

 


목표 아키텍처 구성도

 

참고: [AWS] AWS로 구축하는 3티어 아키텍처

[AWS] AWS로 구축하는 3티어 아키


VPC

VPC & Subnet

사설 IP C 클래스 IP 대역을 사용해 VPC 생성

Subnet은 이중화를 위해 2개의 Availibility Zone(AZ)으로 나눠 생성(고가용성 확보)

AZ당 Public Sunet 1개, Private Subnet 3개를 생성

총 8개의 Sunet으로 네트워크 구성

Routing Table

Public Subnet용 Routing Table(Public RT)와 Private Subnet용 Routing Table(Private RT)로 구성

Public RT은 Internet Gateway로 트래픽을 라우팅하도록 설정

Private RT는 NAT Instance로 트래픽을 라우팅하도록 설정

NAT instance

1. EC2 생성

  • AMI: amzn-ami-vpc-nat

  • Subnet: Public Subnet
  • Security Group: SGnat
  • Public IP: O

2. EC2 설정

  • 대상 확인/변경 중지 처리

3. Routing Table 설정

  • Private Routing Table에 라우팅 대상으로 등록

 


Security

Security Group

Name Desc. Rule
SGnat NAT instance를 위한 보안그룹 HTTP, HTTPS (src: anywhere IPv4),
SSH (src: myIP)
SGdb RDS를 위한 보안그룹 MYSQL/Aurora (src: SGwas)
SGwas WAS를 위한 보안그룹 TCP 8080port (src: SGnlb),
HTTP, HTTPS (src: SGnat),
SSH (src: SGnat)
SGnlb NLB를 위한 보안그룹 TCP 8080port (src: SGweb)
SGweb Web Server를 위한 보안그룹 HTTP (src: SGalb),
HTTP, HTTPS (src: SGnat),
SSH (src: SGnat)
SGalb ALB를 위한 보안그룹 HTTP (src: anywhere IPv4)

 

 

 


 

Database Tier

Subnet Group 생성

정의한 Subnet에 DB instance가 생성되도록 Subnet Group 생성

RDS 생성

MySQL Engine RDS 생성

  • Engine: MySQL 8.0.35
  • Option: 다중 AZ DB 인스턴스
  • Instance: 스탠다드 클래스
  • Storage: 범용 SSG(gp2)
  • Public Access: NO
  • SG: SGdb

파라미터 그룹 수정

시간대는 서울로 정하고, 한글이 깨지지 않도록 수정

 

Name Value
time_zone Asia/Seoul
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_database utf8mb4
character_set_results utf8mb4
character_set_server utf8mb4
collation_connection utf8mb4_general_ci
collation_server utf8mb4_general_ci

 

Failover Test

MySQL에 접근하여 Failover test 진행

  1. DB instance IP 출력 명령어 입력
while true; do host $RDS_Endpoing | grep address; sleep 1; done
  1. RDS > DB 장애조치 실행
  2. Private IP 주소 출력 변경 확인


Application Tier

Instance 생성

  • AMI: Amazon Linux 2023
  • SG: SGwas

프로그램 설정

1. JDK 설치

2. MySQL 설치 및 DB 연동

  • DB 연동을 위한 MySQL Yum Repository 설치

  • DB 연동을 위한 MySQL comminity server 설치

  • MySQL 실행 후 MySQL 접근 확인

  • MySQL Test Data 생성

 

  • Tomcat을 위한 MySQL Connector/J 설치 후 java lib에 위치시킴

 

3. tomcat10 디렉토리에 Tomcat 설치

4. tomcat service 파일 설정 (참고: service란)

[Unit]
Description=Tomcat 10 servlet container
After=network.target

[Service]
Type=forking
User=root
Group=root
Environment="JAVA_HOME=/usr/lib/jvm/java-21-amazon-corretto"
Execstart=/usr/local/tomcat10/startup.sh
ExecStop=/usr/local/tomcat10/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

5. tomcat 실행

6. 별도 경로에 index.jsp 생성

  • WAS 공통점: testDB 데이터베이스의 test 테이블 데이터 출력하도록 함
  • WAS별 차이점: WAS마다 다른 내용 출력하도록 함(WAS A, WAS C)

7. Root Path 설정

  • server.xml에서 Context 설정

8. Tomcat restart

 

TG 생성

  • Protocol: TCP
  • Port: 8080

NLB 생성

  • 체계: 내부
  • SG: SGnlb
  • 리스너 프로토콜: TCP
  • 리스너 포트: 8080
  • NLB AZ 교차 설정: on


Presentation Tier

Instance 생성

  • AMI: Amazon Linux 2023
  • SG: SGweb

프로그램 설정

1. nginx 설치

2. Nginx Redirect 설정

  • Nginx로 접근 시 NLB로 리다이렉트하도록 설정

  • ALB Health check를 위한 Location Block 추가

TG 생성

  • Protocol: HTTP
  • Port: 80

ALB 생성

  • 체계: 인터넷경계
  • SG: SGalb
  • AZ: Public Subnet
  • 리스너 프로토콜: HTTP
  • 리스너 포트: 80
  • Health check 경로: /health

ALB DNS 접근


도메인 설정

도메인 생성 및 매핑

무료 도메인 사이트에서 도메인 생성 후 CNAME에 ALB DNS 매핑

신규 도메인 접근

01-2 컴퓨터 구조의 큰 그림

컴퓨터 구조 
= 컴퓨터가 이해하는 정보(데이터+명령어) + 컴퓨터 4가지 핵심 부품

데이터? 
- 정적인 정보
- 컴퓨터가 주고 받는 정보, 내부에 저장된 정보를 얘기하기도 함

명령어?
- 컴퓨터는 결국 명령어 처리 기계
- 명령어는 컴퓨터를 실질적으로 움직이는 정보
*데이터는 명령어를 위한 재료
- 명령어 예) 1과2를 더하라(1과2는 데이터)

컴퓨터 4가지 핵심 부품(컴퓨터 종류를 막론하고 거의 동일)
- CPU, 메모리, 보조기억장치, 입출력장치
*메모리는 주기억장치의 줄임말. 주기억장치는 원래 2종류(RAM, ROM) 근데 이 학습과정에선 RAM을 지칭한다고 보면 됨

핵심부품이 모이는 판(부착하는 판): 마더보드, 메인보드
메인보드에 부착된 부품 간 정보를 주고 받을 수 있는 통로: 버스
버스  중에서 제일 중요한 버스(like 척추): 시스템 버스

메모리?
- 현재 실행되는 프로그램(프로세스)의 명령어와 데이터를 저장하는 부품
(=프로그램을 실행하려면 데이터와 명령어가 메모리에 있어야한다)
*페이징기법을 사용하면 꼭 메모리에 있어야 하는 건 아닐 수도 있음*
- 메모리의 주요 개념: 주소 ▶️ 접근 또는 필요로하는 데이터나 명령어가 메모리 내 어디에 위치해있는지 알 수 있는 정보

CPU?
- 컴퓨터의 두뇌와 같은 부품☆☆☆
- 메모리에 저장된 명령어를 읽어 들이고 해석하고 실행하는 장치
- CPU 핵심 부품 3가지: ALU(산술논리연산장치), 제어장치(control unit), 레지스터

- ALU? 그냥 계산기임
- 레지스터? CPU 내부에 있은 작은 저장 장치(임시 저장 장치). 보통 CPU 내 여러 개 있음
- 제어장치? 제어신호(컴퓨터의 부품을 관리하고작동시키기 위한 전기신호로 여러 종류가 있다)라는 일종의 전기신호를 내보내고 명령어를 해석하는 장치

제어신호 종류: 메모리 읽기신호, 메모리 쓰기신호
- CPU가 메모리 값 읽고 싶을 때? 읽기 신호
ㄴ CPU가 메모리에 읽기 신호(1번지 읽어)를 보냈다면? 메모리가 명령어를 레지스터에 갖다둠. 그럼 제어장치가 레지스터에 있는 명령어를 해석함 -> 이를 기반으로 다음 처리 수행
- CPU가 메모리에 값을 쓰고 싶을 때? 쓰기 신호

보조기억장치
- 왜 필요해? 메모리(RAM)은 비쌈. 그리고 메모리는 전원 꺼지면 정보를 읽어버림(휘발성 저장장치) ▶️ 전원이 꺼져도 정보를 보관할 수 있는 장치 필요
- 실행되지 않는 프로그램 보관하는 장소
*메모리에는 실행할 정보를 저장하고, 보조기억장치에는 보관할 정보를 저장한다.

메인보드? 
- 컴퓨터의 4가지 핵심 부품을 부착하는 판
- 버스를 통해서 부품 간 정보를 주고 받음

버스?
- 메인보드에 있는 핵심부품들 간에 정보를 주고 받을 수 있는 통로(다양한 종류가 있음)
- 제일 중요한 통로를 시스템 버스라고 함

시스템버스?
- 주소 버스(주소 통로) / 데이터버스(데이터 통로) / 제어 버스(제어신호 통로)로 구성




02-1 0과1로 숫자를 표현하는 방법
컴퓨터의 정보단위. 비트
- 비트(bit): 0과 1로 표현하는 가장 작은 정보 단위
- 프로그램은 수많은 비트로 이뤄져 있음
- 다만 일상적으로 비트라는 단위를 쓰진 않음(바이트, 메가바이트, 킬로바이트, 메가바이트, 기가바이트, 테라바이르..등을 사용)
- 8bit=1byte
- 1,000byte=1kB
- 1,000kB=1MB...
- 1,000MB=1GB
- 1,000GB=1TB

워드(word)
- CPU가 한번에 처리할 수 있는 정보의 크기 단위
- 예1) aCPU가 한번에 32bit씩 처리할 수 있다면 해당 CPU의 1워드=32bit
- 예2) bCPU가 한번에 64bit씩 처리할 수 있다면 해당 CPU의 1워드=64bit
- half word: 워드의 절반 크기
- full word: 워드 크기
- double word: 워드의 2배 크기

0과1로 숫자 표현 방법. 이진법(binary)
- 숫자가 1을 넘어가는 시점에 자리 올림
- 십진법(decimal)은 9 넘어가는 시점에 자리올림
- 이진수로 음수 표현: 2의 보수
ㄴ 어떤 수를 그보다 큰 2^n에서 뺀 값
ㄴ 모든 0과 1을 뒤집고 1을 더하면 됨
ㄴ CPU가 음수와 양수를 구분하는 법: CPU 내부에 플래그 레지스터라는 게 있음. 거기에 양수인지 음수인지 표시되어 있음.
근데 이진법만 쓰면 데이터 길이가 너무 길어짐. 그래서 십육진법 쓰는 경우도 있음
- 0~9까지는 십진법과 동일. 
- 10(십진법)은 a, 11(십진법)은 b...15(십진법)는 f. 16(십진법)에 자리 올림되어서 10
- 코드상 십육진법 표기 시, 0x15라고 표기할 수 있음
- 십육진법 왜 써? 이진수<->십육진수 변환이 쉬움




02-2 0과 1로 문자를 표현하는 법
- 문자집합(character set): 컴퓨터가 이해할 수 있는 문자 모음
- 인코딩(encoding)
ㄴ 코드화 과정
ㄴ 문자를 0과 1의 문자코드로 변환하는 과정
- 디커딩(decoding)
ㄴ 코드 해석 과정
0과1의 문자코드를 문자로 변환하는 과정

아스키코드(대중적인 문자집합)
- 초창기 문자집합
- 7비트로 하나의 문자 표현(8비트 중 1비트는 오류 검출을 위해 사용되는 패리티 비트(parity bit)
- 한글을 포함한 다른 언어 문자 표현 불가
>언어별 인코딩 방식의 등장

한글 인코딩: 완성형 VS 조합형
- 한글 특징: 초성 중성 종성 조합으로 단어가 이루어짐(영어와 다름)
- EUC-KR
ㄴ완성형 인코딩 방식
ㄴ글자 하나에 2바이트(16비트) 크기의 코드 부여함=한 글자를 표현하는데 16진수 4자리가 필요
ㄴ문제점: 지원하지 않는 글자도 있음(뷁, 괗 등)
ㄴ문데점: 다국어 지운 프로그램 개발 시에는 언어벌로 인코딩 방식을 모두 이해해야함
>통일된 문자집합에 대한 니즈 > 유니코드문자집합과 utf 인코딩 방식 탄생

유니코드
- 통일된 문자집합
- 한글 영어부터 이모티콘 특수문자까지 가능
- 현재 문자 표현에 있어 매우 중요
- 인코딩 방식에 따라, 글자를 비트로 변환하는 방식에 따라 utf-8, utf-16...등으로 나뉨




03-1 소스코드와 명령어
- 개발자가 사용하는 언어: python, JAVA..등 고급 언어=개발자가 읽고 쓰기 편하게 만들어진 언어
- 컴퓨터가 이해하고 실행하는 언어: 저급 언어

저급 언어의 종류: 기계어, 어셈블리어
- 명령어로 이루어진 언어: 기계어: 2진수 또는 16진수로 표현됨
- 사람들이 그나마 좀 읽기 편하게 변환된 언어: 어셈블리어
- 어셈블리어는 기계어와 다르게 소스코드에 직접 입력하기도 함

고급언어는 저급언어로 변환되어 컴퓨터가 명령어를 처리함
- 고급>저급언어변환 방식의 종류: 컴파일 방식, 인터프리트 방식
ㄴ 고급언어 중 컴파일 언어 -> 컴파일 방식
ㄴ 고급언어 중 인터프리트 언어 -> 인터프리트 방식

컴파일언어
- 고급언어>저급언어 변환과정을 컴파일이라고 함
- 컴파일러에 의해 고급언어(소스코드)가 저급언어로 변환됨
- 컴파일에 의해 변환된 저급언어는 목적코드라고 함
- 컴파일러가 소스코드 전체를 검토(오류 여부, 미사용 변수 유무, 최적화 가능 여부 등) > 이후 소스코드 전체를 목적코드로 통째로 컴파일 진행
-> 오류가 하나라도 있으면 변환을 진행하지 않음

인터프리트 언어
- 인터프리터라는 특수한 프로그램에 의해 소스코드를 한줄씩 실행됨(저급언어로 변환됨)
- 소스코드 전체가 저급언어로 변환되기까지 기다릴 필요가 없음
- 에러 발생 코드 전까지 다 저급언어로 변환

*cpu종류와 컴파일러 종류에 따라 저급언어가 달리질 수 있음

*컴파일언어, 인터프리터언어가 정확하게 양분되는 건 아님(흑백논리X)




03-2 명령어의 구조 
명령어
=컴퓨터가 수행할 연산+연산에 사용될 데이터가 저장된 위치
=연산코드+오퍼랜드

어셈블리어도 명령어다
=어셈블리어도 연산코드와 오퍼랜드로 이뤄져있다.

오퍼랜드?
- 연산에 사용될 데이터 or 연산에 사용될 데이터가 저장된 위치(오프랜드가 들어가는 공간에는 얘를 훠어어얼씬 더 자주 들어감)
-> 그래서 오퍼랜드를 주소필드라고 부르기도 함
- 하나의 명령어에 오퍼랜드는 없을 때(0주소 명령어)도 1개(1주소 명령어)일 수도, 2개(2주소 명령어)일 수도..여러 개일 수도 있음.

연산코드
- 컴퓨터가 수행할 연산
- CPU마다 갖고 있는 연산코드 종류는 다양한데 그래도 공통적으로 데이터 전송, 산술/논리 연산, 제어 흐름 변경, 입출력 제어가 있음

연산코드의 종류1) 데이터 전송
- 데이터 이동, CPU로 이동, 저장, 스택에 저장, 가져오기 등
*STACK: LAST IN FIRST OUT 구조(한 쪽이 막힌 듯한 구조)
*OUE: FIRST IN FIRST OUT 구조(선입선출 구조)

연산코드 종류2) 산술/논리 연산
- 사칙연산코드, 오퍼랜드에 더하기/빼기해라, and/or/not, true/false비교해라

연산코드 종류3) 제어 흐름 변경
- 특정 메모리 주소로 실행의 순서를 옮기는 연산
- 조건 부합하면 딴 데부터 수행해라, 실행 순서 바꿔라, 실행을 멈춰라

연산코드 종류4) 입출력 제어 

주소필드를 쓰는 이유
- 크기가 제한되어 있음 -> 들어갈 수 있는 데이터 크기가 제한됨 

유효주소: 연산에 사용될 데이터가 저장된 위치

명령어 주소 지정 방식
- 연산에 사용할 데이터가 저장된 위치를 찾는 방법
- 유효 주소를 찾는 방법
- 다양한 명령어 주소 지정 방식들
- 종류1) 즉시 주소 지정 방식
ㄴ 연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시 -> 오퍼랜드 크기가 제한되기에 사용가능한 데이터가 한정됨. 근데 데이터를 찾아다니지 않아도 되서 간단하고 빠름
- 종류2) 직접 주소 지정 방식
ㄴ 오퍼랜드 필드에 유효 주소를 직접 명시
ㄴ 유효 주소를 표현할 수 있는 크기가 연산코드만큼 줄어듦.
- 종류3) 간접 주소 지정 방식
ㄴ 유효주소의 주소를 명시하는 방식 -> 느림
- 레지스터 주소 지정 방식
ㄴ 연산에 사용될 데이터가 저장된 레지스터 명시
ㄴ CPU가 메모리보단 레지스터에 접근하는 게 훨 빠름(레지스터는 CPU 안에 있음. 메모리는 CPU 밖에 있음)
- 종류4) 레지스터 간접 주소 지정 방식
ㄴ 연산에 사용할 데이터를 메모리에 저장하고 이 주소를 저장한 레지스터를 오퍼랜드 필드에 명시




03 추가: c언어의 컴파일 과정
컴파일과정: 전처리기>컴파일러>어셈블러>링커




04-1 ALU와 제어장치
CPU를 구성하는 부품
ALU는 계산해는 장치
제어장치는 제어 신호를 발생시키고 명령어를 해석하는 장치

ALU가 받아들이는 정보
- 레지스터한테서 피연산자를 받아들임
- 제어장치로부터 제어신호(수행할 연산)를 받아들임
>ALU는 위 정보를 바탕으로 계산 수행. 그리고 이 결과값을 레지스터로 내보냄
?왜 메모리가 아닌 레지스터에 저장? CPU가 메모리에 접근하는 것보다 레지스터에 접근하는 게 훨 빠름.
추가로 플래그라는 것도 내보냄. 플래그란? 연산정보에 대한 부가정보. 이건 플래그 레지스터라는 곳으로 내보냄
*연산결과가 음수이먄 음수라는 플래그값이, 0이면 0이라는 플래그값이 플래그 레지스터에 담김. 오버플로우여부(연산결과가 연산결과를 담을 수 있는 레지스터보다 큰 경우)도 플래그에 명시됨

플래그 레지스터는 0과 1로 표현됨. 예를 들어 제로플래그가 1이면 연산결과가 0이라는 걸 표현한 거임. 

제어장치가 받아들이는 정보: 클럭, 해석할 명령어, 플래그
- 클럭? 제어장치가 받아들이는 신호. 컴퓨터의 모든 부품을 일사분란하게 움직일 수 있게 하는 단위. 시계처럼 일정 주기로 발생하는 신호. 클러규신호 단위에 맞춰 명령어가 수행됨. 
- 해석할 명령어? 명령어 레지스터라는 특수한 레지스터에 저장됨. 이걸 받아들이고 이를 해석하여 제어신호를 내보냄.
- 플래그? Cpu가 받아들이는 부가정보. 근데 명령어 해석과정에서도 필수적인 정보임.
- 제어신호? 제어신호는 사실 제어장치만 발생시캘 수 있는게 아니라서 받아들임

제어장치
- cpu내부용, cpu와부용이 있음
- cpu내부용은 레지스터와 alu에 전달하는 신호가 있음
- cpu외부용은 메모리와 입출력장치에 전달하는게 있음




04-2 레지스터
레지스터: CPU 내부에 있는 작은 임시 저장장치
- 프로그램 속 명령어와 데이터는 실행 전후로 레지스터에 저장 > 이거 프로그래머가 관찰할 수도 있음
- LOWLEVEL개발자는 이 레지스터 까보는 경우도 많음.
레지스터 종류는 다양(CPU마다 종류도 다름)하고 역할도 다 다름.

종류1) 프로그램카운터
- 메모리에서 가져올 명령어의 주소 저장
종류2) 명령어 레지스터
- 해석할 명령어를 저장함(메모리에서 갓(방금) 읽어 들인 명령어)
종류3) 메모리 주소 레지스터
- 메모리의 주소를 저장함
- cpu가 주소버스로 정보 내보낼 때 거치는 레지스터
종류4) 메모리 버퍼 레지스터
- 메모리와 주고받을 값(데이터, 명령어)을 저장
- 데이터버스로 주고받을 때 거치는 레지스터
종류5) 플래그 레지스터
- 연산결과 또는 cpu상태에 대한 부가적인 정보
종류6) 범용 레지스터
- 다양하고 일반적인 상황에서 자유롭게 쓸 수 있음(주소도, 데이터도 담을 수 있고 그리고 얘는 여러 개가 있음)
종류7) 스택 포인터 > 주소 지정에 사용
- 스택 주소 지정 방식에 사용.
- 스택의 꼭대기, 즉 스택이 어디까지 차있는지를 알려주는 레지스터
*스택은 메모리 안에 있음(스택 영역)
종류8) 베이스 레지스터 > 주소 지정에 사용
- 변위 주소 지정 방식에 사용되는 레지스터
- 오퍼랜드 필드 값을 변위로 보고 특정 레지스터 값을 더하여 유효 주소를 얻음(오퍼랜드 필드 + 레지스터값)
ㄴ 방식1)오퍼랜드 필드 값+프로그램카운터(상대 주소 지정 방식)
ㄴ 방식2) 오퍼랜드 필드 값+베이스 레지스터



01-2 컴퓨터 구조의 큰 그림 ~ 04-2 레지스터까지

 

'컴퓨터 구조' 카테고리의 다른 글

04-3 명령어 사이클과 인터럽트  (1) 2024.06.07

기초 명령어

pwd ▶ 나는 어딘가?

ls ▶ 이 디렉토리에는 뭐가 있는가?

cd /${디렉토리명} ▶ 여기로 드가자

ㄴ예) cd /var/log

ㄴ cd log

ㄴ cd .. ▶ 뒤로 가자잉

mkdir ${디렉토리명} ▶ 이거 만들어줘(make directory 약어)

vi blahblah.txt ▶ blahblah 텍스트파일 열어줘(없어면 만들어서라도 열어라잉)

cp blahblah.txt ▶ 이거 복사본 만들어줘

mv blahblah.txt {위치시킬 경로} ▶ 저기로 옮겨줘

rm blahblah.txt  ▶ 이거 없애줘

wget ${URL} ▶ URL 파일 다운받아줘(web get 약어)

git clone ${git repository 주소} 리포지토리 이거 다운받아잉

 

 

 

+ Recent posts