Docker 개요
만약에 내가 개발하고 있던 환경에서는 잘 돌아갔지만, 배포 서버에서는 잘 돌아가지 않는 경우가 있을 수 있습니다. 그리고 하나의 서버 안 즉 EC2안에서 여러개의 프로그램이 돌아가게 할 수 있습니다. 위 그림에서 프로그램 3개가 유기적으로 연결되어 있지는 않습니다. 또한 각 프로그램의 환경을 따로 분리하고 싶다고 해 봅시다. 왜냐하면 프로그램1에서 깐 django 3.6버전이 프로그램2에는 영향을 미치게 하고 싶지 않을 수도 있기 때문이죠. 이러한 니즈에 의해 Docker가 사용됩니다.
위와 같은 문제점은 Docker가 아니더라도 가상환경으로 어느정도 해결할 수 있습니다. 위에서 django나 많은 의존성을 깔 때 python의 가상환경을 만들어 주었었던것과 비슷하게요. 하지만 엄청난 비효율성이 생기게 되는데, 가상환경에 컴퓨팅파워를 할당해주는데, 이게 놀고있을 수도 있기 때문입니다. 당연히 하나의 환경이 놀고있으면 컴퓨팅파워를 줄이고 유동적으로 조절할 수도 있습니다. 하지만 힘듭니다.
반면에 Docker는 컨테이너 형태로 환경을 구분해줍니다. 또한 이미지를 통해 같은 환경의 가상 컴퓨터(컨테이너)를 무한히 생성할 수 있게됩니다. 이전에 autoscaling group을 할떄 이를 체험해보았습니다. 즉 컨테이너를 만들면 이에대한 이미지를 만들 수 있게 됩니다. 그럼 이 이미지를 바탕으로 똑같은 환경의 컨테이너를 무한히 생성해 낼 수 있게 되는 것입니다.
다음과 같이 도커를 도식화 할 수 있습니다.
그리고 만약에 마이크로서비스와 같이 하나의 서버에서 프로그램이 돌아가야 하는데, 이들간의 환경이 공유가 필요한 경우가 있을 수 있습니다. 이러한 상호작용을 하기 위해서는 이러한 컨테이너들 위에 무언가가 하나 더 있어야 합니다. 이게 Docker-Compose입니다.
우리는 이제 앞으로 위와같은 환경 구성을 만들겁니다. Container2개를 만들고 하나는 django, 하나는 nginx를 위한 환경을 구축합니다. 이들은 Docker-Compose에 가두어 집니다. 그리고 여기서 발생할 수 있는 문제점이 django의 wsgi의 socket을 바라보고 nginx와 통신을 하기 때문에, django가 먼저 올라가고 nginx가 올라가야 합니다. 즉 우리는 여기서 연관성을 집어넣어줄 수 있습니다.
container2에 container1이 있어야지 동작할 수 있다라고요. 이렇게 하게되면 Container2가 올가가기 전에 Container1이 올라가서 실행된겁니다. 그리고 User가 Nginx의 80번 포트를 바라보고 Nginx가 django의 8000번 포트로 가게 해야 합니다. 이 떄 Container간의 포트? 와 같이 관계를 관장하는 것이 Docker-Compose라고 할 수 있겠습니다.
실습 ( 본 실습은 생활코딩 Docker강의를 바탕으로 진행됩니다. )
우선 저는 리눅스에서 도커를 활용하기 전에 제 맥북에서 docker를 설치하고 간단한 실습을 진행해 보도록 하겠습니다.
https://docs.docker.com/desktop/mac/install/
여기 들어가서 docker desktop을 설치하고 일단 터미널에 sudo docker images라고 치면 이비지의 목록이 나오게 되는데 이쯤하면 설치는 다 잘 된것입니다.
우리는 맥북 app store에서 다은 받은 것을 program이라고 하고, docker hub에서 다운 받은 것을 imagte라고 합니다. 우리는 앞으로 docker hub에서 찾고자 하는 이미지를 다운 받을 것입니다. 그리고 program이 실행되면 process가 실행되는 것이고 image를 실행하면 container를 실행합니다. 또한 program이 다양한 프로세스를 가질 수 있는 것과 마찬가지로 image도 다양한 container를 가질 수 있습니다.
dockerhub에서 image를 다운받는 것을 pull이라고 하고, image를 run하게 되면 conatiner에서 실행되도록 조치되어 있는 것을 실행하게 되는 것입니다.
우선 httpd image를 다운받는 과정을 진행해 보도록 하겠습니다.
https://docs.docker.com/engine/reference/commandline/pull/
docker cli의 공식문서를 참고하여 docker pull httpd명령어를 실행해 줍니다.
그리고 docker images를 통해서 설치한 httpd image의 다양한 정보를 확인할 수 있습니다.
또한 이는 docker desktop에서 확인할 수도 있습니다.
그다음에는 run을 하는 방법을 알아보도록 하겠습니다.
당연히 docker desktop으로도 image를 run할 수 있지만 저는 docker cli를 이용하여 진행해 보도록 하겠습니다.
이렇게 실행하고 프로세스를 확인할 수도 있습니다. 지금 실행중인 도커 컨테이너를 확인하려면
다음과 같이 docker ps로 확인하면 됩니다. 이제 이 컨테이너를 종료 시켜보도록 하겠습니다.
하지만 이는 종료된 것이지 다시 시작시킬 수 있습니다. 완전히 삭제된 것이 아니기 때문이죠 docker ps에 -a옵션을 주게 되면 종료된 컨테이너 목록을 다 확인해 볼 수 있습니다.
그리고 이를 다시 시작하고, 프로세스 목록을 확인하고 다시 로그를 보려면 아래와 같은 명령어를 치시면 됩니다.
그리고 삭제하려면 docker rm을 해주시면 컨테이너가 삭제되게 됩니다. 그리고 삭제하기 전에 도커 컨테이너를 꺼주셔야 합니다.
다음과 --force옵션을 주게되면 종료를 꼭 안하셔도 됩니다. 그리고 또한 이미지를 삭제하려면 docker rmi를 쳐주시면 됩니다. 저는 이전에 만든 httpd이미지를 삭제해 보도록 하겠습니다.
이제 도커와 네트워크와 관련된 내용을 간단히 알아보도록 하겠습니다.
간단히 이 그림을 통해 알아보도록 하겠습니다. Container를 담는 운영체제를 저희는 Host라고 하고 Container, Host모두 각기 다른 File System을 가지고 있습니다. 그리고 만약에 Container에 Web server를 구축하였다면 정적 파일을 Client에게 서빙하는 역할을 하죠. 또 Host, Container마다 각기 다른 포트를 가지고 있게 됩니다. 그리고 만약에 클라이언트가 Host로 들어오게 된다면 Container는 들어온지도 모를겁니다. 그래서 Host의 Port와 Container의 Port를 연결시켜주는 작업을 해 줄 필요가 있습니다.
Host의 80번 포트와 Container의 80번 포트를 연결해 주어 실행하는 명령어는 docker run -p 80:80 httpd와 같이 작성해 주면 됩니다. 이렇게 포트를 신호를 전달하는 것을 포트포워딩이라고 합니다.
이제 다시 이미지를 pull하고 포트포워딩을 진행해 보도록 하겠습니다.
다음과 같이 httpd를 다시 pull했고 8081 -> 80로 포트포워딩 해주었습니다. 그리고 http://localhost:8081/index.html을 들어가게 되면 아래와 같은 화면과 위에 GET /index.html이렇게 로그가 찍힙니다.
이제 직접 docker conatiner로 쉘을 열어서 저 index.html파일을 수정하는 법에 대해서 알아보겠습니다.
이렇게 docker exec를 활용하면 되는데 -it를 꼭 붙여줘야 바로 쉘과의 인터렉션이 끊어지지 않습니다. 그리고 그 뒤에는 /bin/bash로 열어달라는 소리입니다 이웨에도 본쉘인 /bin/sh를 활용한거나 zsh를 활용해도 됩니다.
그리고 httpd의 공식문서에 index.html이 위치해 있는 경로를 찾고 수정하는 과정을 진행합니다.
또한 docker container는 최소한의 환경에서 돌아가는 것이기 때문에 vim같은 텍스트 편집기가 없습니다. 따라서 apt update && apt-get install vim을 통해서 vim을 깔고 vim index.html을 열어서 아래와 같이 변경해 줍니다.
그리고 http://localhost:8081/index.html을 들어가서 잘 변경되었나 확인해 보면 아래와 같습니다.
그리고 docker container를 삭제하게 된다면 우리가 수정한 index.html파일이 사라지게 됩니다. 당연히 container는 단순히 필요할 때만 사용하면 되는 것이기에 이런 것은 불가피 합니다. 만약에 Host의 파일 시스템과 container의 파일 시스템을 연결할 수만 있다면 버전관리가 용이할 수 있겠다고 생각합니다. 이래서 docker는 -v(Volume)옵션을 제공합니다.
다음과 같이 Host의 ~/Desktop/Coding/DevOps/docker/htdocs파일과 container의 /usr/local/apache2/htdocs를 연결하면서 httpd이미지를 이용해 컨테이너를 생성하고 Host의 index.html을 아래와 같이 수정하고 http://localhost:8888/index.html을 확인해 보겠습니다.
~Desktop/Coding/DevOps/htdocs/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
Hello, Docker!!(Host index.html)
</body>
</html>
다음과 같이 정상적으로 Host와 Container파일 시스템이 연결된 것을 확인할 수 있습니다. 이상으로 튜토리얼을 마치겠습니다.