[Docker] Docker로 배포 경험하기
오늘은 원티드에서 주최하는 프리온보딩 강의 첫 날이다!
따라가기 벅차지 않을 까 걱정도 했는데 멘토님이 생각보다 친절히 알려주시고 질문도 잘 받아주셔서 편하게 수업을 들었던 거 같다.
바로 오늘 배운 수업에 대해 알아보자!!
CI/CD 란?
지속적 통합 (Continuous Integration, CI): 개발자들이 코드 변경 사항을 중앙 저장소에 자주 병합하는 것을 말한다. 각 병합 시 마다 코드를 자동으로 빌드하고 테스트하여, 개발 초기 단계에서 문제를 발견하고 수정할 수 있게 한다. 이 과정은 통합 과정에서 발생할 수 있는 문제를 최소화하여, 소프트웨어의 품질 을 향상시킨다.
지속적 배포 (Continuous Deployment): 모든 코드 변경 사항이 테스트를 통과한 후 자동으로 운영 환경에 배포되는 것을 의미한다.
지속적 전달 (Continuous Delivery): 지속적 배포의 한 단계 전 과정으로, 모든 코드 변경 사항이 테스트를 통과하면 운영 환경에 배포될 준비가 되는 것을 의미한다.
ECR(Elastic Container Registry): AWS(Amazon Web Services)에서 제공하 는 도커 컨테이너 이미지를 저장, 관리, 배포할 수 있는 완전 관리형 컨테이너 이미지 레지스트리 서비스이다. 개발자는 ECR을 사용하여 컨테이너 이미지를 쉽게 업로드하고, 버전 관리하며, 배포 작업을 보다 효율적으로 수행할 수 있다.
모던 웹개발에서 Docker 가 왜 필요해졌을까?
컨테이너는 무엇일까?
컨테이너를 왜 사용하는가?
"자신이 해결해야 할 문제가 과연 제대로 된 문제인지 처음부터 신중하게 고려하기 바란다. 가령 다음 지 침은 성능 문제의 탈을 쓰고 있지만 사실상 구현 문제를 제기한다. ‘성능을 높이기 위 해 애플리케이션을 마이크로서비스 단위로 쪼개고 컨테이너화시킬 것’. 제대로 된 문제는 다음과 비 슷하다. ‘고객들의 목표 완수 시간을 단축하기 위해 애플리케이션 성능을 5% 향상시킬 것’. 후자는 결과 성공 여부를 측정할 수 있는 실질적 메트릭metric을 포함하고 있으며 실현 방법도 마이크 로서비스 구현으로 한정 짓지 않는 다."
- from. '자바 개발자를 위한 데브옵스 툴'
컨테이너가 걸어온 역사
1960~70년대 - 한 컴퓨터가 한 애플리케이션 실행을 담당하는 것이 일반적이고, 프로세스도 오래 걸린다.
프로세스란?
프로세스는 운영 체제에서 실행 중인 프로그램의 인스턴스이다. 컴퓨터의 CPU 시간과 메모 리 자원을 할당받아 실행되며, 최소 하나 이상의 실행 흐름(스레드)을 가진다. 운영 체제는 멀티태스킹을 통해 여러 프로세스를 동시에 관리하고 실행할 수 있다. "프로그램의 인스턴스"라는 표현은 프로그램이 메모리에 로드되어 실행 상태에 있는 그 실행 중인 복사본을 의미한다. 쉽게 설명하면, 프로그램은 디스크에 저장된 코드와 데이터의 정적인 집합이다. 사용자나 시스템에 의해 실행될 때, 운영 체제는 해당 프로 그램의 코드와 데이터를 메모리로 로드하고 실행을 시작한다.
이 때 메모리에 로드되어 실행되는 프로그램을 "인스턴스"라고 부른다. 예를 들어, 텍스트 편집기 프로그램이 하드 드라이브에 저장되어 있을 때는 실행 가능 한 코드의 모음일 뿐이다. 사용자가 이 텍스트 편집기를 실행할 때마다, 운영 체제는 프로그램의 복사본을 메모리에 로드하며, 이 로드된 복사본이 바로 "프로그램의 인스턴스"가 된다. 사용자가 여러 창을 열어 동시에 여러 문서를 편집하는 경우, 각 창은 텍스 트 편집기 프로그램의 별도 인스턴스로 작동한다.
kernel란?
커널과 프로세스는 운영 체제 내에서 밀접하게 연관된 두 요소이다. 커널은 운영 체제의 핵심 부분으로, 하드웨어와 소프트웨어 간의 통신을 관리하며, 시스템 자원과 다양한 컴퓨터 작업을 효율적으로 조정하고 제어한다. 프로세스는 실행 중인 프로그램의 인스턴스로, 커널에 의해 생성되고 관리된다. 이 두 요소의 연관 관계는 다음과 같다.
- 프로세스 생성과 관리: 커널은 프로세스의 생성, 실행, 중지 및 종료와 같은 생명 주기를 관리 한다. 사용자나 다른 프로그램에 의해 프로그램이 실행되면, 커널은 해당 프로그램에 대한 프로세스를 생성하고, 필요한 시스템 자원(예: CPU 시간, 메모리 공간)을 할당한다.
- 자원 할당: 커널은 여러 프로세스 간에 하드웨어 자원(CPU, 메모리, I/O 장치 등)을 공정하게 분배한다. 이는 멀티태스킹 환경에서 중요한 역할을 하며, 각 프로세스가 필요한 자원을 효율적으로 사용할 수 있도록 한다.
- 프로세스 간 통신: 프로세스들이 서로 정보를 교환하거나 동기화할 필요가 있을 때, 커널은 이러한 통신을 가능하게 하는 메커니즘(IPC: Inter-Process Communication)을 제공한다. 예를 들어, 파이프, 메시지 큐, 공유 메모리 등이 있다.
- 보안과 격리: 커널은 프로세스 간의 격리를 유지하여, 하나의 프로세스가 다른 프로세스의 메모리나 자원에 무단으로 접근하는 것을 방지한다. 이는 시스템의 안정성과 보안을 유지하는 데 중요하다.
- 스케줄링: 커널은 프로세스 스케줄러를 통해 어떤 프로세스가 CPU를 사용할 차례인지 결정 한다. 이는 시스템의 반응 시간과 처리량을 최적화하는 데 중요한 역할을 한다.
즉, 커널은 프로세스의 생성부터 종료까지 전 생명 주기에 걸쳐 관리하는 역할을 하며, 프로세스들 이 시스템 자원을 효율적으로 사용하도록 조정한다. 이러한 관리와 조정을 통해, 사용자와 애플리 케이션은 안정적이고 효율적인 시스템 환경에서 작업을 수행할 수 있다.
컴퓨팅 자원을 최대한 쉐어해서 써서 빠르게 만들자 -> 여러 사용자가 자원을 사용 하게 되면서 서로 간섭이 일어나는 경우가 생겨버림 -> 한명의 사용자가 시스템을 중단시켜버리는 경우 까지 발생 -> 하나의 프로그램이 사용하는 리소스를 다 사용해버리는 경우나 프로그램 에러가 나서 OS 까지 영향을 미쳐버리는 상황이 발생!
그럼 어떻게 해야할까?
자원을 분리해서 사용해야 함!!
'가상화'(virtualization)를 사용해서 하나의 컴퓨터에서 여러 애플리케이션 구동
하이퍼바이저 가상화는 하드웨어 상에 여러 개의 독립적인 가상 운영 체제(가상 머신)를 실행할 수 있게 해주는 기술이다. 이를 통해 하나의 물리적 컴퓨터 내에서 여러 운영 체제를 동시에 실행할 수 있다. 각 가상 머신은 독립적인 컴퓨팅 환경을 제공받으며, 기본적인 하드웨어 자원(CPU, 메모리, 스토리지 등) 은 물리적 호스트 시스템에 의해 가상화된 형태로 할당된다.
하이퍼바이저 가상화의 핵심은 하이퍼바이저라는 소프트웨어에 있다. 하이퍼바이저는 물리적 하드웨어 와 가상 머신 사이에서 중재자 역할을 하며, 하드웨어 자원을 가상 머신에게 분배하고, 가상 머신들이 이 자원을 안전하고 효율적으로 사용할 수 있도록 관리한다.
가상화를 통해, 개발자는 다양한 운영 체제 위에서 애플리케이션을 테스트하고, IT 관리자는 서버를 더 효율적으로 활용하여 비용을 절감하며, 보안성이 높은 격리된 환경을 구성할 수 있다.또한, OS 가상화는 클라우드 컴퓨팅, 재해 복구, 시스템 마이그레이션과 같은 다양한 IT 요구 사항을 충족시키는 데 핵심적인 역할을 한다.
하이퍼바이저란?
하이퍼바이저는 가상화 환경을 생성하고 관리하는 소프트웨어 또는 펌웨어의 핵심 구성 요소다. 그 주요 역할은 하나의 물리적 시스템 상에 여러 개의 독립된 가상 머신(VM)을 실행할 수 있는 환경을 제공하는 것이다. 이 과정에서 하이퍼바이저는 다음과 같은 중요한 기능을 수행한다.
- 자원 할당 및 관리: 하이퍼바이저는 CPU, 메모리, 스토리지 등의 물리적 하드웨어 자원을 가상 머신에게 가상화된 형태로 할당하고 관리한다. 이는 각 가상 머신이 독립적인 운영 체제와 애플리케이션을 실행할 수 있는 독립된 환경을 가질 수 있게 한다.
- 가상 머신 실행 및 모니터링: 하이퍼바이저는 가상 머신의 생성, 실행, 중지 및 삭제와 같은 생명 주기를 관리한다. 또한, 가상 머신의 성능과 자원 사용을 모니터링하여, 전체 시스템의 효율성과 안정성을 유지한다.
- 격리 및 보안 유지: 하이퍼바이저는 가상 머신 사이에 강력한 격리를 제공한다. 이는 각 가상 머신 이 다른 가상 머신의 자원에 접근하거나 영향을 미치지 못하도록 보장하여, 시스템의 보안성을 강화한다.
- 네트워킹 관리: 가상 네트워크 인터페이스와 스위치를 통해 가상 머신 간의 네트워크 통신을 가능 하게 하며, 필요에 따라 외부 네트워크와의 연결도 관리한다.
하이퍼바이저는 이러한 기능을 통해 가상화 기술의 핵심적인 장점인 자원 활용 최적화, 유연한 인프라 관리, 비용 절감 등을 실현한다.
컨테이너란?
VM 과 다른 방법을 사용해서 효율 성능이 더 나아진 게 컨테이너
컨테이너 가상화는 애플리케이션을 실행하는 데 필요한 코드, 런타임, 시스템 도구, 시스템 라이브러리 등을 포함하 는 가벼운, 격리된 환경을 생성하는 기술이다. 컨테이너는 가상 머신과 달리 운영 체제 수준에서 격리되며, 하나의 호스트 시스템에서 여러 컨테이너를 실행할 수 있어 자원을 효율적으로 사용한다. 리눅스의 핵심 격리 기술을 기반 으로 하여, 하나의 리눅스 커널 위에서 여러 개의 독립적인 사용자 공간 인스턴스를 실행할 수 있게 해준다. 이러한 격리는 주로 리눅스의 두 가지 핵심 기능, 즉 Cgroups(Control Groups)와 네임스페이스(Namespace)를 활용하 여 이루어진다.
Cgroups (Control Groups)란?
Cgroups는 프로세스 그룹의 리소스 사용량(예: CPU 시간, 시스템 메모리, 네트워크 대역폭)을 모니터링하고 제한하는 기능을 제공한다. 이를 통해 각 컨테이너가 할당된 자원을 초과하여 사용하는 것을 방지함으로써, 시스템의 안정성을 유지하고 다른 컨테이너 또는 시스템 전체에 미치는 영향을 최소화한다.
네임스페이스는 프로세스에게 제한된 시스템 뷰를 제공하여, 프로세스가 자신의 네임스페이스 내에서만 시스템 리소스를 볼 수 있도록 한다. 이를 통해 파일 시스템 마운트, 네트워크, 사용자 ID, 호스트 이름 등을 각 컨테이너마다 독립적으로 할당하고 관리할 수 있다. 네임스페이스는 컨테이너를 격리된 환경으로 만들어 주는 핵심 기술로, 컨테이너 내부에서 실행되는 프로세스가 호스트 시스템이나 다른 컨테이너 의 리소스와 충돌하지 않도록 한다.
Cgroups 와 네임스페이스 는 리눅스 커널의 두 가지 핵심 기술로, 컨테이너 가상화의 기반을 이룬다. 여기서 각각에 대한 예시를 들어보겠다.
Cgroups (Control Groups) 예시
예를 들어, 시스템에 여러 컨테이너가 실행 중이고, 각각 다른 애플리케이션이 작동하고 있다고 가정해보자. 여기서 한 컨테이너가 너무 많은 CPU 시간을 사용하여 시스템의 다른 부분에 영향을 미치기 시작한다면, 시스템 관리자는 Cgroups를 사용하여 그 컨테이너의 CPU 사용량을 제한할 수 있다. 예를 들어, cpu.shares 파라미터를 조정하여 특정 컨테이너 그룹이 사용할 수 있는 CPU 자원의 양을 조절할 수 있다. 이는 시스템 자원이 공정하게 분배되도록 보장하고, 한 애플리케이션이 전체 시스템을 점유하는 것을 방지한다.
네임스페이스 (Namespace) 예시
네임스페이스는 시스템 리소스를 격리하여 프로세스 그룹이 해당 리소스를 독립적으로 보고 관리 할 수 있게 한다. 예를 들어, PID (Process ID) 네임스페이스 를 사용하는 경우, 각 컨테이너는 자체적인 PID 1부터 시작하는 고유한 프로세스 번호 공간을 가지게 된다. 이는 컨테이너 내부에서 실행되는 프로세스가 시스템의 다른 부분이나 다른 컨테이너의 프로세스와 독립적으로 관리될 수 있음을 의미한다. 결과적으로, 컨테이너 내부의 애플리케이션은 자신이 전체 시스템에서 유일하게 실행되고 있는 것처럼 동작할 수 있으며, 이는 보안과 격리를 강화한다.
- 리눅스의 이러한 격리 기술을 사용함으로써, 컨테이너 가상화는 각 컨테이너에게 겉보기에는 완전히 독립된 시스 템처럼 보이는 환경을 제공한다. 이는 개발자가 애플리케이션을 개발하고 배포할 때 발생할 수 있는 "작동하지 않음" 문제를 크게 줄여주며, 애플리케이션의 이식성을 크게 향상시킨다.
Docker 기본 개념과 구조
도커 엔진 (Docker Engine)란?
도커 엔진은 컨테이너를 생성하고 관리하는 기능을 제공하는 클라이언트-서버 형태의 애플리케이션
이는 세 가지 주요 구성 요소로 이루어져 있다.
- 도커 데몬: 컨테이너 관리를 위한 백그라운드 프로세스로, 이미지 생성, 컨테이너 실행, 네트워크 설정 등의 작업 을 수행한다. 이는 컨테이너의 생성, 실행, 중지와 같은 생명 주기를 관리한다. 또한, 이미지를 빌드하고 저장소에서 이미지를 가져오는 역할을 수행한다. 도커 데몬은 다른 도커 클라이언트의 명령을 수행하기 위해 REST API를 통해 접근할 수 있다.
- REST API: 도커 데몬과 통신하는 인터페이스로, 이 API를 통해 다양한 도커 클라이언트가 도커 데몬과 상호작용할 수 있다. 이를 통해 애플리케이션의 배포, 관리, 확장을 위한 다양한 명령을 수행할 수 있다.
- CLI 클라이언트: 사용자가 커맨드 라인을 통해 도커 엔진과 상호작용할 수 있게 하는 인터페이스다. 사용자는 이를 통해 컨테이너를 생성하고 관리할 수 있으며, 이미지를 빌드하고 도커 허브 같은 이미지 저장소와 상호작용할 수 있다.
동작방식
도커 엔진의 동작 방식은 기본적으로 컨테이너의 생명 주기 관리와 관련된 일련의 과정을 포함한다. 사용자 또는 애플리케이션은 도커 CLI 또는 API를 통해 도커 데몬과 상호작용하며, 도커 데몬은 이러한 명령을 수행하여 컨테이너를 생성, 실행, 중지 등의 작업을 관리한다. 이 과정에는 여러 단계가 포함되는데, 아래에서 구체적으로 살펴보겠다.
- 이미지 다운로드 또는 빌드: 컨테이너를 실행하기 전에, 도커 엔진은 해당 애플리케이션을 실행하는 데 필요한 모든 파일과 설정이 포함된 도커 이미지가 필요하다. 사용자는 도커 허브나 다른 이미지 저장소에서 이미지를 다운로드하 거나, Dockerfile 을 정의하고 이를 통해 새로운 이미지를 빌드할 수 있다.
- 컨테이너 생성: 이미지가 준비되면, 사용자는 도커 데몬에게 컨테이너 생성을 요청한다. 이때, 네트워크 설정이나 볼 륨 마운트와 같은 추가적인 옵션을 지정할 수 있다. 도커 데몬은 이러한 정보를 바탕으로 새로운 컨테이너의 인스턴 스를 생성한다.
- 컨테이너 실행: 컨테이너가 생성되면, 도커 데몬은 컨테이너 내부에서 정의된 애플리케이션을 실행한다. 이 과정에 서 컨테이너는 독립된 파일 시스템, 네트워크 인터페이스, 프로세스 ID 공간 등을 갖게 되며, 이는 컨테이너를 호스 트 시스템과 격리된 환경에서 실행되게 한다.
- 컨테이너 관리: 도커 엔진은 실행 중인 컨테이너의 상태를 모니터링하고 관리한다. 사용자는 도커 CLI를 통해 실행 중인 컨테이너를 조회하고, 로그를 확인하며, 필요한 경우 컨테이너를 중지, 재시작 또는 삭제할 수 있다. 5. 리소스 관리: 도커 엔진은 Cgroups와 네임스페이스와 같은 리눅스의 핵심 기능을 사용하여 컨테이너의 리소스 사 용량을 제한하고, 컨테이너 간의 격리를 유지한다. 이를 통해 시스템의 안정성을 보장하고, 다른 컨테이너나 시스템 전체에 부정적인 영향을 미치는 것을 방지한다.
용어 정리
Docker Image
도커 이미지는 컨테이너를 실행하기 위한 불변의 템플릿이다. 이 이미지는 애플리케이션 실행에 필요한 모든 것을 포함한다 — 코드, 런타임, 애플리케이션과 관련된 라이브러리, 환경 변수 및 설정 파일 등. 도커 이미지는 여러 계층으로 구성되어 있으며, 각 계층은 변경 사항을 저장한다. 이미지는 컨테이너를 생성하는 데 사용되며, 일반적으로 도커허브와 같은 레지스트리에서 가져오거나 Dockerfile 을 사용해 직접 빌드할 수 있다.
Docker container
도커 컨테이너는 도커 이미지의 실행 인스턴스이다. 컨테이너는 이미지를 기반으로 하여 실행되며, 격리된 환경에서 애플리케이션과 그 의존성을 캡슐화한다. 컨테이너는 가벼우며 시스템 리소스를 효율적으로 사용한다는 장점이 있다. 컨테이너는 시작될 때 생성되고 종료될 때 제거된다. 개발자는 동일한 이미지를 사용하여 여러 컨테이너를 동시에 실행할 수 있으며, 각 컨테이너는 독립적으로 실행되고 관리된다.
DockerFile
Dockerfile 은 도커 이미지를 자동으로 빌드하기 위한 스크립트 파일이다. 이 파일은 기본 이미지 설정, 실행할 명령어, 추가할 파일 및 디렉토리, 환경 변수 설정 등 이미지 생성에 필요한 지시어를 담고 있다. Dockerfile 은 docker build 명령어와 함께 사용되어 새로운 도커 이미지를 생성한다.
Dockerfile 을 사용하면 애플리케이션의 배포 과정을 표준화하고 자동화할 수 있으며, 필요한 모든 설정과 의존성이 문서화되어 재현 가능하다.
Docker Hub
도커허브는 도커 이미지를 찾고, 공유하고, 관리할 수 있는 공식적인 클라우드 기반 서비스 및 저장소이다. 사용자는 도커허브에서 수많은 공개 도커 이미지를 무료로 다운로드할 수 있으며, 자신의 도커 이미지를 업로드하여 공개하거나 비공개로 저장할 수도 있다. 도커허브는 개발자와 조직이 컨테이너화된 애플리케이션을 쉽게 배포하고 공유할 수 있도록 지원하는 중앙 집중식 서비스이다. 도커허브는 또한 자동 이미지 빌드, 웹훅, 조직 및 팀을 위한 협업 툴 등과 같은 추가 기능을 제공한다.
Docker Registry
도커 리지스트리는 도커 이미지를 저장하고 배포하기 위한 서버 측 응용 프로그램이다. 도커허브와 유사하게 동작하지만, 도커 리지스트리는 사용자가 자신의 서버에 직접 설치하여 개인 또는 조직 내부에서 사용할 수 있는 프라이빗 저장소를 만들 수 있게 해준다. 이는 비공개 프로젝트나 내부적으로 사용되는 이미지를 안전하게 관리하고 싶은 조직에 적합한 솔루션이다. 도커 리지스트리는 보안, 액세스 제어, 저장소 한계 설정 등을 사용자가 직접 구성할 수 있게 해주며, 이를 통해 개인화된 컨테이너 이미지 저장소를 운영할 수 있다. 도커 리지스트리 소프트웨어는 오픈 소스이며, Docker Inc.에 의해 관리된다.
참조 문헌 : 원티드 day01 오시영님의 강의자료
실습 과제
Docker 기본 명령어
cheatsheet https://docs.docker.com/get-started/docker_cheatsheet.pdf
명령어 구성 : docker 커맨드 (옵션) 대상 (인자)
docker --version: Docker의 버전 정보를 출력
docker run = docker pull + docker create + docker start: Docker 이미지를 바탕으로 새로운 컨테이너를 생성하고 시작
(docker pull로 이미지를 가져오고, docker create로 컨테이너를 생성한 다음, docker start로 컨테이너를 실행하는 절차를 포함)
컨테이너 생명 주기
create : 컨테이너를 생성하지만 시작하지 않음
start : 생성된 컨테이너를 시작
stop : 실행 중인 컨테이너를 정지
rm (remove) : 컨테이너를 삭제
docker ps -a : 모든 컨테이너를 나열(실행 중이지 않은 컨테이너도 포함)
windows: powershell : docker ps -aq | ForEach-Object {docker rm -f $_}
mac : docker rm -f $(docker ps -aq)
: 실행 중인 모든 컨테이너를 강제로 삭제(-f 옵션은 강제 실행을 의미)
명령어 찾아서 보기
https://docs.docker.com/reference/cli/docker/container/rm/
실습1 - 아파치 서버 띄우기
docker run --name apa02 -d -p 8080:80 httpd : 이름이 apa02인 아파치(httpd) 이미지를 바탕으로 한 컨테이너를 생성하고 백그라운드에서 실행, 호스트의 8080 포트와 컨테이너의 80 포트를 연결
docker ps : 실행 중인 컨테이너를 확인
localhost:8080 접속 -> 아파치 웹 서버의 홈페이지를 볼 수 있음
성공!!
docker stop apa02 : apa02 컨테이너를 정지
docker rm apa02 : apa02 컨테이너를 삭제
docker ps -a : 모든 컨테이너를 나열(실행 중이지 않은 컨테이너도 포함)
실습2 - 아파치 서버 여러대 띄우기
docker run --name apa03 -d -p 8081:80 httpd : 컨테이너에 apa03라는 이름을 할당(-d: 컨테이너를 백그라운드에서 실행)
호스트의 8081 포트와 컨테이너의 80 포트를 연결 > 호스트의 8081 포트로 들어오는 트래픽을 컨테이너의 80 포트로 전달
docker run --name apa04 -d -p 8082:80 httpd
docker run --name apa05 -d -p 8083:80 httpd
docker ps : 현재 실행 중인 컨테이너의 목록 출력
docker stop 컨테이너이름
docker rm 컨테이너이름
docker ps -a
실습3 - 이미지 삭제
컨테이너 삭제 후 진행해야함
docker rm 이미지이름 이미지이름 이미지이름 (위에서 컨테이너 삭제 완료)
docker ps -a
docker image ls : 설치된 Docker 이미지 목록출력
docker image rm httpd : httpd 이미지를 삭제
docker image ls : 이미지 목록 재출력
이미지가 삭제된 것이 확인됐다!!
마무리
아직은 첫 실습이라 기본 명령어부터 생소하고 확 와닿진 않지만
명령어를 치고 하나하나 결과가 나올 때마다 자바를 처음 배웠을 때의 감정이 되살아나서 재밌으면서도 다음 수업이 기대가 된다.
기본 명령어들을 잘 복습해서 강의 진도를 못 따라가는 일이 없도록 해야지..!