
만약에 물리적인 서버 3대에 서비스가 운영되는 환경이라고 가정하자.

기존 서버 구성과 도커를 활용한 구성
운영 환경과 일치하는 테스트 환경을 만드는 가장 쉬운 방법은 3대의 물리적인 서버를 운영하는 것이다.
But, 테스트 환경이라 트래픽 부하 시 서버의 확장 등은 고려할 필요가 없다.(서버 성능도 운영 서버보단 낮은 것을 택할거임)
그렇다 하더라도 3대의 물리적인 서버를 유지, 보수하는 것은 매우 귀찮은 일이다. 또한, 새로운 마이크로서비스가 추가될 때마다 테스트 환경에서도 물리적인 서버가 추가되면서 점점 유지보수해야 할 인프라가 쌓여만 갈 것이다...
Docker는 이렇게 여러 마이크로 서비스를 한 대의 물리적인 서버에서 운영할 수 있도록 만들어 준다.(심지어 언어 제한도 없다 ..!)
-> 모든 언어(js, python, rust 등)의 애플리케이션을 한 대의 물리적인 서버에서 운영 가능하다.
이를 가능하게 해주는 기술은 "Cgroup"과 "Namespace"이다.
Control Group의 약자로, 시스템의 CPU 시간, 시스템 메모리, 네트워크 대역폭과 같은 자원을 제한하고 격리시키는 커널 기능
시스템 리소스를 해당 프로세스에만 해당되는 자원처럼 보이도록 하고, 다른 프로세스와 격리시키는 가상화 기능
현재 Namespace는 6가지 기능을 제공하고 있는데,
UTS -> hostname을 분할
IPC -> 프로세스 간 통신 격리
PID -> 실행 프로세스 분할 관리
MNT -> 파일 시스템의 마운트 지점 분할 격리
NET -> 네트워크 리소스와 관련된 정보 분할
USER -> user, group을 분할
이 두개의 기술이 바로 도커 컨테이너의 핵심이라는 말씀 !
-> VMWare처럼 물리적인 가상화를 사용하지 않아도 인프라를 운영함에 있어 더 좋은 성능을 보장한다.

-> 대부분의 개발 프로세스는, 개발자가 코딩 해서 SVN, GIT과 가은 코드 저장소에 Commit을 하고 Build를 요청하면 CI/CD를 담당하는 서버나 서비스가 해당 소스 파일을 원하는 환경으로 배포함.
이 과정에서 도커를 적용시키면 어떻게 해야될까?
배포 과정은 다음과 같다.
도커로 이 과정을 진행시키기 위해서는 압축된 파일의 역할을 하는 무언가가 필요할텐데 그것이 바로 Docker Image이다.
그래서 도커 이미지가 뭔데 !!
도커 이미지는 도커를 실행하기 위해 필요한 컨테이너의 시초
도커 이미지 리스트를 보는 명령어를 실행할건데, 다음은 로컬에 존재하는 모든 도커의 이미지를 보여주는 명령어이다.
$ docker images

당연히 처음 도커를 접해본 사람에게는 이미지가 존재하지 않을테니, 도커 이미지를 다운로드 하는 명령어를 실행시킨 후, 다시 도커 이미지를 조회하면 된다.
$ docker pull nginx

이제 이미지가 준비됐으니 이미지를 컨테이너화 시켜서 도커를 실행한다.
$ docker run --name nginx -p 8000:80 -d nginx

-> 다음과 같은 명령어를 실행하게 되면 해시값 하나를 결과값으로 출력받게 된다..!

우리가 실행시킨 nginx 도커 컨테이너가 잘 실행 되는지 확인하고 싶으면 다음과 같은 명령어를 실행시키면 된다.
$ docker ps

nginx 도커 컨테이너의 정보를 확인할 수 있고, 잘 실행되고 있는지 확인했다면 브라우저에서도 이를 확인해본다.

웹 브라우저 주소창에 http://localhost:8000을 입력하여 접속해보면 nginx의 페이지가 나오게 된다.
그럼 이제 Docker Hub에서 다운로드 받은 이미지가 아닌, 이미지를 만들려면 어떻게 해야될까?
앞에서 말했듯이 도커 이미지는 말 그대로 컨테이너의 스냅샷 기능이다.
이미지는 변경이 불가능한 파일인 반면 컨테이너의 파일은 수정이 가능하다. 그러므로 컨테이너의 파일을 수정하고 이미지를 만들면 된다.
Nginx의 index.html 페이지 문구를 바꿔볼 것이다. 이때 Nginx 컨테이너 안의 index.html 파일의 위치를 아지 곰르기 때문에 nginx에 접속해서 이 파일의 위치를 찾을 것이다.
호스트 PC에서 도커로 연결하는 명령어는 attach가 있다.
attach로 연결하면 nginx에 접속할 때 로그를 확인할 수 있는데, 터미널에 접속해서 index.html 파일의 위치를 찾아 우리가 만든 index.html로 바꿀 것이기 때문에 터미널 환경으로 접속하려면 먼저 호스트 PC에서 도커 컨테이너의 쉘을 실행시켜야한다.(외부 -> 내부)
이때 호스트에서 도커 컨테이너 안에 명령을 실행하는 명령어는 "exec"
$ docker exec -it nginx /bin/bash

다음과 같이 도커 컨테이너 내부 쉘이 실행되어 접근했다.
그래서 리눅스 쉘에 접근하여 명령어를 입력하고 쉘을 표시하기 위해 -it 옵션을 붙인 것이다.
쉘에 접근을 했으니 이제 파일을 찾아야한다.
-> find /(루트 디렉토리) -name(파일 이름 지정 옵션)을 통해 찾아보자.

여기서 2>/dev/null은 정상 출력이 아닌 에러 출력을 /dev/null로 보내버리는 방식임.
위 명령어를 통해 index.html의 위치가 /usr/share/nginx/html/index.html이라는 것을 알 수 있었다.
이제 컨테이너 내의 index.html 파일을 호스트 PC에 복사하는 명령어를 실행한다.
$ docker cp nginx:/usr/share/nginx/html/index.html index.html

이제 호스트에서 index.html 파일을 편집하여 다시 컨테이너로 복사한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to nginx!</title>
<style>
/* Reset and global styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: 'Segoe UI', Tahoma, Verdana, Arial, sans-serif;
color-scheme: light dark;
}
body {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f6d365 0%, #fda085 100%);
color: #333;
text-align: center;
padding: 20px;
}
/* Card container */
.card {
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 20px 30px;
max-width: 500px;
width: 100%;
}
h1 {
font-size: 2rem;
color: #ff6347; /* Tomato color for emphasis */
margin-bottom: 1rem;
}
p {
font-size: 1rem;
line-height: 1.6;
margin-bottom: 1rem;
}
a {
color: #0078d7;
text-decoration: none;
font-weight: bold;
}
a:hover {
text-decoration: underline;
}
em {
color: #555;
font-style: italic;
}
/* Responsive design */
@media (max-width: 600px) {
h1 {
font-size: 1.5rem;
}
p {
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="card">
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/" target="_blank" rel="noopener noreferrer">nginx.org</a>.<br>
Commercial support is available at
<a href="http://nginx.com/" target="_blank" rel="noopener noreferrer">nginx.com</a>.
</p>
<p><em>Thank you for using nginx.</em></p>
</div>
</body>
</html>

기존 index.html은 너무 별로라, 이쁘게 꾸며 보았다 ㅎㅎ
이제 수정한 index.html 파일을 nginx 컨테이너에 복사해서 넣을 것이다.
하지만, docker 명령을 하는 디렉토리에는 우리가 만든 index.html 파일이 존재해야한다. 이때 ls 명령어를 사용하여 index.html 파일이 있는지 먼저 확인한다.
$ docker cp /Users/hongttochi/Desktop/index.html nginx:/usr/share/nginx/html/index.html

컨테이너를 index.html 파일이 수정된 현재 상태의 이미지로 만든다.

다시 이미지를 조회한다.

다음과 같은 결과를 보게 되면 mynginx라는 이미지를 볼 수 있다. 여기까지 왔다면 당신은 이미지 만드는 데 성공한 것 !!
기존에 실행되는 nginx 컨테이너를 종료하고 삭제시킨다.
"여기서 잠깐 !! 실행되고 있는 컨테이너는 삭제되지 않는다. 그렇다면 어떤 방법으로 삭제를 해야될까?"
바로 실행을 종료 시키고, 삭제하는 것이다.(중지시키지 않고 삭제하면 stop하고 삭제하라고 오류 메시지 날라옴 ❌)
종료 명령어는 docker stop [컨테이너 이름], 삭제 명령어는 docker rm [컨테이너 이름]이다.
$ docker stop nginx
$ docker rm nginx

다음과 같은 명령어를 실행시키고 나면 리스트에서 사라지고, 웹 브라우저도 더이상 접속되지 않는다는 것을 확인할 수 있다.
그렇다고 정지를 하고 무조건 삭제를 하는 것은 아니다. 만약에 다시 시작하고 싶으면 docker start [컨테이너 이름]을 하여 시작할 수 있고, 또 정지된 컨테이너를 보고싶으면 ps 명령어에 -a 옵션을 추가하자
$ docker ps -a
도커 컨테이너를 run 명령어로 실행시킬 때 -name 옵션을 붙이지 않으면 이름을 자동으로 생성되는데, 삭제할 때 컨테이너의 이름을 모른다면 Container ID 값으로도 삭제가 가능하기 때문에 당황하지는 말자.(필자는 당황했었다 😅)
이제 저장된 새 이미지를 베이스로 컨테이너를 만들어보자.
명령어는 이전과 같겠지만, 이미지명을 새로 만든 이미지의 이름으로 바꿔야 한다.
$ docker run --name nginx -p 8000:80 -d mynginx
이렇게 스냅샷 형태로 이미지를 만들 수 있고, Dockerfile을 활용하여 이미지를 제작할 수 있다.
실제로 Github에서 레포를 둘러보면 Dockerfile들이 있는 것을 확인할 수 잇다. 그만큼 개발자들은 도커 이미지를 제작할 때 스냅샷보다는 도커 파일을 많이 사용한다는 것이다.
도커 파일은 이미지를 명령어 묶음으로 만들 수 있는 TXT 파일 -> 파일에 텍스트로 명령어를 기술하여 실행하면 이미지가 만들어진다.
이번에는 스냅샷으로 만들었던 이미지를 Dockerfile을 활용하여 제작해볼 것이다.
vi 편집기로 Dockerfile을 만들고 다음과 같은 소스를 입력 후 저장한다.

도커 파일을 이용하여 이미지를 만드는 명령어를 실행해볼 것인데, 이때 주의할 점이 위에서 작성한 Dockefile이 현재 작업 디렉토리에 위치해있어야한다.

이제 도커 이미지를 조회해보자.

결과를 보다시피, mynginx2 이미지가 생성된 것을 확인할 수 있다. 이제 마찬가지로 컨테이너를 실행시켜보자.
스냅샷으로 만든 컨테이너를 8000포트로 실행시켰기때문에 구분짓기 위해 -name과 -p 번호를 수정하여 다음과 같은 명령어를 실행시킨다.
$ docker run --name custom -p 8002:80 -d mynginx2
이제 http://localhost:8002 에 접속하게 되면 스냅샷으로 만든 이미지와 똑같은 index page가 보일 것이다.(http://localhost:8000 으로 접속해도 똑같은 페이지가 나옴)
ps) Docker Hub에서 다운로드 한 도커 이미지 중 안 쓰는 이미지를 삭제하고 싶으면 docker rmi[REPOSITORY] or [IMAGE ID]를 활용하여 삭제한다.