도커가 뭘까
Docker
- Docker는 애플리케이션 구축, 구현 및 테스트를 위해 격리된 가상화 환경을 생성하는 서비스형 플랫폼이다.
- Docker는 컨테이너 엔진으로 리눅스 커널 기능을 사용하여 운영 체제 위에 컨테이너를 만들고,Docker 자체는 서비스의 컨테이너를 관리하는 데몬으로 실행된다.
- Linux 커널의 도커 엔진
-
- namespace: 프로세스를 독립시켜주는 가상화 기술이다. 각 컨테이너에서 실행된 프로세스가 시스템(user, 파일, 네트워크, 호스트명, 프로세스)등에 대해 독립할 수 있게 해준다.
- cgroups: 자원(CPU, 메모리, network bandwidth)에 대한 제어를 가능하게 해주는 리눅스 커널의 기능이다.Docker는 컨테이너라는 가상의 '격리 환경'을 만들기 위해 리눅스의 namespace과 cgroup이라는 기능을 사용한다. (namespace와 cgroup으로 만들어진 컨테이너를 LXC라고 부른다)
Docker image
- 파일로 어필리케이션 실행에 필요한 독립적인 환경을 포함
- Aplication을 포장 및 전송하기 위해서 사용
- 소스 코드, 라이브러리, 종속성, 도구 및 응용 프로그램을 실행하는데 필요한 기타 파일을 포함하는 불변파일
- 도커 컨테이너 == 실행 중인 이미지
- 컨테이너는 수정가능하지만 이미지는 수정 불가능함
- 컨테이너 실행에 필요한 파일과 설정 값 등을 포함하고 있는 것. (상태값을 가지지 않고 변하지 않음, Immutable)
Docker Container
- 가상화된 런타임 환경
- 응용프로그램을 빠르고 쉽게 시작할 수 있는 portable units 이다
- 이미지를 실행한 상태로 볼 수 있고, 변하는 값은 컨테이너에 저장됨.
Docker Volume
- Docker volume이란 디렉토리를 매핑하는 것입니다.
- 즉, Docker host의 디렉토리와, container의 디렉토리를 연결하는 것입니다.
- 도커에서 데이터 영속성을 보장하기 위한 방법 중 하나!
Docker Images VS Container
- 컨테이너가 존재하려면 이미지를 실행해야하지만, 이미지는 컨테이너 없이 존재할 수 있다.
- 도커 컨테이너는 실행 중인 이미지 인스턴스로 간주함
Dockerfile --(Build)--> Image --(Create)--> Container
출처:
https://sunrise-min.tistory.com/entry/Docker-Container와-Image란-무엇인가
https://velog.io/@geunwoobaek/컨테이너-및-도커-개념정리
VM vs Docker
virtual machine
: 자원을 똑 떼어내서 가상 환경에 할당해주기 때문에 쓸 수 있는 자원에 한계가 많음. 그리고 각자 독립된 os를 가지고 있기 때문에 무거움
docker
: host자원을 공유하기 때문에 컨테이너가 필요한 만큼 자원을 끌어다 쓸 수 있고 os를 host와 공유하고 있기 때문에 가벼움
VM은 docker에 비해 메모리나 자원에 관해서 처음부터 정해놓고 실행하기에 비효율적이고 확장성이 떨어진다
Docker의 작동방식
도커는 이미지를 통째로 생성하지 않고, 바뀐 부분만 생성한 뒤 부모 이미지를 계속 참조하는 방식으로 동작하는데, 이것을 레이어라고 한다
출처:
https://avengersrhydon1121.tistory.com/287
Dockerfile 작성법
Dockerfile
- docker에서 이미지를 생성하기 위한 용도로 작성하는 파일 (이미지 정보를 적어둔 템플릿과 유사함)
- 흔히 cd 이미지를 떠올려보면 쉽게 이해할 수 있다고 생각한다. 컨테이너는 이미지를 바탕으로 만든다고 생각하면 된다.
Dockerfile cmd
- FROM베이스 이미지 : 어느 정도 기본적이 구성요소들이 갖추어진 상태의 이미지
- 도커파일에서 베이스 이미지를 지정하는 지시어
- RUN명령어가 실행된 후의 변경사항이 새 이미지에 반영된다.
- command를 실행하여 새 이미지에 포함시키는 역할
- CMDRUN과의 차이 :
- RUN은 이미지를 빌드할 때 실행
- CMD는 이미 만들어진(빌드 완료된)이미지로부터 도커 컨테이너를 시작할 때 실행
- (컨테이너가 실행되었을 때 명령이 실행됨)
- 컨테이너가 시작될 때 실행할 커맨드를 지정하는 지시어
- ENTRYPOINTCMD와 달리 컨테이너 실행 시 param값을 대체할 수 없다
- FROM ubuntu ENTRYPOINT ["/bin/echo", "Hello"] CMD ["world"] $ docker run -it --rm --name test Hello world $ docker run -it --rm --name test toramko Hello toramko => CMD의 param인 'world'가 대체된다
- 컨테이너가 시작 시 실행될 command를 지정
- COPY
- Host 내에 있는 파일 또는 디렉토리를 컨테이너의 파일시스템으로 복사
- WORKDIR
- 작업 디렉토리를 설정한다
- ADD단순히 로컬 파일 또는 디렉토리를 Docker 이미지로 복사하려는 경우에는 COPY를 사용하는 것이 적절하다.
- COPY와 같이 복사하는 것이지만 복사하려는 대상파일이 압축파일인 경우 파일의 압축을 해제하여 복사함
#FROM : Docker Base Image (기반이 되는 이미지, <이미지 이름>:<태그> 형식으로 설정)
FROM debian:bullseye
#WORKDIR : "RUN", "CMD", "ENTRYPOINT" 명령이 실행될 작업 디렉터리
WORKDIR /etc/mysql
#COPY : 파일 복사
COPY ./tools/entrypoint.sh /entrypoint.sh
#RUN : Shell Script 또는 명령을 실행
RUN chmod +x /entrypoint.sh
#ENTRYPOINT : 컨테이너가 시작되었을 때 스크립트 실행
ENTRYPOINT ["/entrypoint.sh"]
#CMD : 컨테이너가 실행되었을 때 명령이 실행
CMD ["mysqld"]
Docker-Compose 란
Docker-Compose
- 여러 컨테이너를 가지는 애플리케이션을 통합적으로 만들고, 각각의 컨테이너를 시작 및 중지하는 작업을 더 쉽게 수행할 수 있도록 도와주는 도구
- 여러대의 컨테이너(독립된 컴퓨터라고 생각하면 됨)를 적절하게 연결하고 관리하는 기술
Docker-Compose Command
- 기본 명령중지 : docker-compose stop
- 실행하면서 빌드(서비스 시작 전 이미지를 새로 만든다) : docker-compose up --build
- 실행 : docker-compose up
Docker-Compose.yml 작성양식
- build
- 해당 서비스의 이미지를 빌드하기 위한 Dockerfile이 위치하는 경로를 저장한다.
- ports
- 호스트 OS와 컨테이너의 포트를 바인딩시켜준다.
- 따옴표와 함께 문자열로 지정해야 한다.
- 형식은 “host:container” 또는 “container”
- 외부로 노출시킬 포트의 맵핑을 명시하는 부분
- 바인드(bind)가 필요한 호스트 외부 포트와 컨테이너 내부 포트를 지정
- image
- docker-compose 안에서 베이스 이미지를 지정한다.
- command
- 해당 서비스가 올라올 때 Dockerfile의 CMD 명령문을 무시하고 실행할 명령어를 설정한다.
- depends_on
- 서비스 간의 종속성 순서대로 서비스를 시작한다.
- A: depends_on: -B A 애플리케이션이 올라오기 전에 B가 먼저 올라와야 한다.
- environment
- 컨테이너의 환경 변수를 지정한다.
dumb-init
PID1
https://swalloow.github.io/container-tini-dumb-init/
- VM 대신에 Docker를 이용하는 이유 중 하나..
- PID 1으로 등록된 단 하나의 프로세스만을 Container가 담당하겠다는 의미, 단 하나의 Container가 곧 단 하나의 서비스 (프로세스)를 의미하여 서버의 환경 관리 측면에서 일관성을 갖게 한다.
- 이와 같은 측면에서 임의의 Loop과 tail -F, bash와 같은 행위가 금지됨
- ⇒ Container의 실행이 곧 서비스의 실행으로 이어지지 않는 행위
- 대다수의 OS에서 첫번째 Process ID 즉, PID 1은 초기에 실행되는 init process가 할당 받는다. init은 고아프로세스를 입양하기 때문에 모든 프로세스의 직/간접적인 부모 프로세스가 된다.
- 컨테이너에선 init 프로세스가 없기 때문에 가장 먼저 실행된 일반 애플리케이션이 PID 1을 할당 받게 된다. 이 경우 크게 두 가지가 문제가 된다.
- 첫째로 정상적인 시그널 처리를 하지 못할 수 있다. ⇒ 일반 애플리케이션은 다른 프로세스를 관리할 목적으로 실행된 것이 아니기 때문에 적절한 시그널 핸들러를 가지고 있지 않을 가능성이 크기 때문이다.
- 둘째로 고아프로세스를 처리할 수 없어진다. ⇒ 고아프로세스는 PID1을 새로운 부모 프로세스로 취급하게 되며 PID1이 고아프로세스의 종료상태를 회수하며 좀비 프로세스가 되는 것을 방지한다. 하지만 이러한 역할을 하지 못하는 일반 애플리케이션의 경우 이러한 문제를 막을 수 없다.
dumb-init
- dumb-init은 이러한 문제를 해결하고 컨테이너를 일반 프로세스와 같은 형태로 사용할 수 있도록 지원하기 위해 만들어짐
- 아래와 같은 예시로 프로세스 트리를 만들었다
- - docker run (on the host machine) - dumb-init (PID 1, inside container) - python my_server.py (PID 2, inside container)
- dumb-init은 모든 signal에 대해 signal handler를 등록하고 해당 signal을 프로세스 세션으로 전달합니다. 파이썬 프로세스는 더 이상 PID 1로 실행되지 않기 때문에 dumb-init이 TERM과 같은 신호를 전달할 때 handler를 등록하지 않아도 프로세스 종료가 가능합니다.
- dumb-init은 signal propagation 뿐만 아니라 고아 상태가 된 자식 프로세스를 거두는 역할도 수행합니다.
Tini
Tini는 컨테이너에 사용할 수 있는 작고 간단한 init입니다. 이는 단일 자식을 생성하고 신호 전달을 수행할 뿐만 아니라 좀비 프로세스를 수확하는 동안 자식이 종료될 때까지 기다리는 방식으로 작동합니다.
docker-compose.yml에서 service부분에 init:true를 통해 생성이 가능하다
init: true 옵션을 사용하면 Docker 컨테이너가 시작될 때 tini라는 초기화 프로세스가 실행됩니다.
이 옵션은 컨테이너 내에서 프로세스를 정상적으로 종료하고 신호를 처리하는 데 도움이 됩니다.
특히, tini는 좀 더 신속하게 종료 시그널을 처리하고 좀 더 안정적으로 컨테이너를 종료하는 데 도움이 됩니다.
NGINX
NGINX란?
- 가볍고 높은 성능을 가진 Web Server
- HTTP Server로 활용되며 정적 파일들을 처리하기 위해 사용
- Reverse Proxy Server로 활용됨
- 80번 포트로 들어오는 내용을 3000, 4000, 9000 등의 다른 포트로 분산 시켜줌
nginx directives
- simple directive : 이름과 값이 있고 세미콜론으로 끝난다.
- worker_process 1;
- block directive : 블럭을 통해서 여러 directive 를 감싼 형태로 정의된다.
- http { server { location / { root /path/to/html; } location /images/ { root /path/to/image; } } }
nginx.conf 구문 구조
- http
- http 블록은 HTTP 통신과 관련된 모듈의 지시어 블럭을 정의하는 블럭이다.
- http, server, location 블럭은 계층구조를 가지고 있어서 http 블럭안에 server 와 location 블럭이 위치할 수 있다.
- 계층구조에 따라서 상위 블럭에서 정의한 지시어는 하위 블럭에 값이 상속된다.
- 예를들어 http 블럭에서 정의한 값은 server 블럭의 기본값이 되고 server 블럭에서 정의한 값을 location 블럭의 기본값이 된다.
- 만약 하위 블럭에서 해당 설정을 새로 정의하면 상위 지시어는 무시되고 새로 정의된 값으로 설정된다. http 블럭 안에 한 개 이상의 server 블럭을 선언할 수 있다.
- server
- 하나의 호스트를 선언하는데 사용하는 블럭으로 http 블럭 안에서만 사용할 수 있다. server 블럭에는 한 개 이상의 location 블럭을 선언할 수 있다.
- location : location 블럭은 server 블럭 안에 정의되고, 특정 url 을 처리하는 방법을 정의한다.
- 처음 요청이 들어왔을 때 보여줄 페이지들이 속해있는 경로와 초기 페이지인 index 지정
- url로 접속했을 경우 index.html, index.htm으로 정의된 파일들을 보여줌
- listen
- 해당 포트로 들어오는 요청을 해당 server {} 블록의 내용에 맞게 처리하겠다는 뜻
- server_name
- 호스트 이름 지정
- 가상 호스트가 있는 경우 해당 호스트명을 넣으면 되고, 로컬에서 작업하고 있는 내용을 nginx를 통해 띄우려고 하는 경우에는 localhost라고 적으면 됨
- error_page
- 요청 결과의 http 상태코드가 지정된 http 상태코드와 일치할 경우 해당 url로 이동
- 보통 403, 404, 502 등의 에러처리를 위해 사용
- location : location 블럭은 server 블럭 안에 정의되고, 특정 url 을 처리하는 방법을 정의한다.
- 하나의 호스트를 선언하는데 사용하는 블럭으로 http 블럭 안에서만 사용할 수 있다. server 블럭에는 한 개 이상의 location 블럭을 선언할 수 있다.
- events
- events 블럭은 네트워크의 작동 환경을 설정하는 블럭이다.
- events 블럭의 지시어는 events 블럭 내부에서만 사용할 수 있고, http, server, local 블럭과는 상속 관계를 가지지 않는다.
- worker_connections# worker_processes * worker_connections 를 계산한 값이 nginx 서버의 최대 접속자 수이다.
- # worker process 가 동시에 처리할 수 있는 접속자 수를 정의한다.
출처 : https://jammdev.tistory.com/217
WordPress
Wordpress는 PHP를 기반으로 한 설치형 블로그이다.
PHP와 HTML 코드 편집 없이도 다시 정리할 수 있는 위젯이 포함되어 있고, 테마도 설치해 자유롭게 전환할 수 있다. 테마 안의 PHP와 HTML 코드는 좀 더 세분화된 맞춤 페이지를 위해 편집할 수 있다.
WP-CLI
wp-cli는 Wordpress의 커맨드라인 인터페이스이다. 웹브라우저 없이 CLI 환경에서 Wordpress를 설정할 수 있게 해준다. 컨테이너 이미지를 설계할 때 유용하다.
WP-CLI는 PHAR로 작성된 유틸리티로써 명령어로 Wordpress 를 관리할 수 있는 유틸리티이다.
플러그인 관리, 워드프레스 업그레이드등의 관리 작업을 커맨드로 실행할 수 있으므로 자동화된 관리가 가능하며 다수의 워드프레스 사이트를 손쉽게 운영할 수 있는 장점이 있다.
PHP
PHP(PHP: Hypertext Preprocessor)는 C언어를 기반으로 만들어진 서버 측에서 실행되는 서버 사이드 스크립트 언어입니다.
PHP는 동적 웹 페이지를 쉽고 빠르게 만들 수 있도록 해주는 데 그 목적이 있습니다.
PHP로 작성된 코드를 HTML 코드 안에 추가하면, 웹 서버는 해당 PHP 코드를 해석하여 동적 웹 페이지를 생성합니다. 출처 : https://tcpschool.com/php/php_intro_intro
CGI & Fast CGI
CGI는 Common Gateway Interface의 약자로 웹서버와 외부 프로그램을 연결해주는 표준화된 프로토콜이다. 웹서버로 요청이 들어왔을 때 그것이 웹서버가 처리 할 수 없는 정보일 때 그 정보를 처리 할 수 있는 외부 프로그램을 호출해서 외부 프로그램이 처리한 결과를 웹서버가 받아서 브라우저로 전송하는 것이다. 외부 프로그램은 C, C++PerlPHPPython 등 어떤 언어로든 작성될 수 있는데, 이것이 가능한 것은 웹서버와 외부 프로그램 사이에 통용되는 공통의 규칙이 정의되어 있기 때문이다.
Apache, Nginx 등의 웹 서버를 쓰고 PHP 프로그래밍이나 Python 프로그래밍 등의 여러가지 언어를 쓰는데 이것들이 문제 없이 사용할 수 있는 것은 그 사이에 CGI라는 표준이 있기 때문이다.
속도를 개선한 것이 FastCGI다. FastCGI는 여러 개의 request가 들어와도 이미 만들어져있는 process를 공유해서 처리하기 때문에 process를 생성하고 삭제하는데 소요되는 리소스, 시간 등이 절약된다.
PHP-FPM는 PHP FastCGI Process Manager의 약자로 PHP를 FastCGI 모드로 동작하게 해준다. 하나의 process로 여러 개의 request들을 처리해주는 manager인 것이다.
네트워크 연결방법
Docker Network
Docker Network란 같은 호스트 내에서 실행중인 컨테이너 간 연결할 수 있도록 돕는 논리적 네트워크 개념이다.
- Docker 컨테이너끼리 통신할 때는 Docker 네트워크를 통해 수행
- Docker는 기본 네트워크 값으로 bridge, hosts, none 세 개의 네트워크를 만듦
- bridge : 네트워크는 하나의 호스트 컴퓨터 내에서 여러 컨테이너들이 서로 소통할 수 있도록 해줍니다.
- host : 네트워크는 컨테이너를 호스트 컴퓨터와 동일한 네트워크에서 컨테이너를 가동하기 위해서 사용됩니다.
- none : 네트워크는 네트워크를 사용하지 않는 것입니다.
Docker Compose Network
docker-compose network의 driver도 docker network와 동일하다.
docker-compose에 있는 컨테이너들은 기본적으로 ". yml파일이 있는 디렉토리명_default"로 동일한 네트워크를 가지게 된다.
compose는 우선적으로 네트워크를 먼저 생성하고 container를 구동시킨 후 네트워크에 연결해준다.
docker-compose down를 할 때에도 마찬가지로 종료, 제거한 후 네트워크를 제거한다.
출처 : https://velog.io/@hyeseong-dev/docker-docker-container-네트워크
https://developer-eun-diary.tistory.com/145
SSL/TLS
- 보안 소켓 계층(Secure Sockets Layer, SSL) 인증서는 브라우저(사용자의 컴퓨터)와 서버(웹사이트) 사이의 암호화된 연결을 수립하는 데 사용됩니다.
- 전송 계층 보안(Transport Layer Security, TLS)은 SSL의 향상된, 더욱 안전한 버전입니다. SSL이 더욱 일반적인 용어이기 때문에 DigiCert는 보안 인증서를 여전히 SSL로 언급하지만 DigiCert에서 SSL을 구입하면 가장 신뢰할 수 있는 최신 TLS 인증서를 얻을 수 있습니다.
- 암호화된 통신을 하는 프로토콜인 HTTPS를 서버에서 구현하기 위해서 위 기업이 발급한 인증서가 필요한데 이런 발급 기관을 **CA(Certificate Authority)**라고 한다.
- self-signed SSL 인증서는 자체적으로 발급받은 인증서이며, 로그인 및 기타 개인 계정 인증 정보를 암호화한다. self-signed SSL 인증서를 만드는 방법 중 하나는 무료 오픈소스인 openssl을 이용해 만드는 것이다. HTTPS를 위해 필요한 인증서파일(.crt)을 openssl이 발급해준다.
- TLS란
- 인터넷에서의 정보를 암호화해서 송수신하는 프로토콜
- TLS v1.2/v1.3 특징
- Handshake 과정에서 필요한 서로간의 통신 횟수가 TLS 1.3버전에서 줄어들면서 키 교환에 따른 필요 시간이 단축 됨
- SSL/TLS
- SSL : 암호화 기반 인터넷 보안 프로토콜이다.
- TLS : SSL의 업데이트 버전
HTTP/HTTPS
- HTTP
- HTTP(Hypertext Transfer Protocol)는 클라이언트와 서버 간 통신을 위한 통신 규칙 세트 또는 프로토콜
- 사용자가 웹 사이트를 방문하면 사용자 브라우저가 웹 서버에 HTTP 요청을 전송하고 웹 서버는 HTTP 응답으로 응답
- 웹 서버와 사용자 브라우저는 데이터를 일반 텍스트로 교환
- HTTPS
- HTTP의 확장 버전 또는 더 안전한 버전
- HTTPS에서는 브라우저와 서버가 데이터를 전송하기 전에 안전하고 암호화된 연결을 설정
- 80
- HTTP가 문서화되기 이전부터 보통 사용하지 않는 빈 포트 번호였다.
- 1991년 HTTP 0.9 버전에서 처음으로 문서화되면서 기본 포트로 지정되었다.
- 443
- RFC 1700 이전까지는 빈 포트 번호였다.
- Kipp E.B. Hickman의 요청으로 1994년 10월에 RFC 1700 문서에 443이 추가되었다.
- 443인 이유는 빈 칸에 순서대로 배정하다 보니 그렇게 된 것 같다.