본문 바로가기
리눅스&OS

구글 클라우드 서버(GCP)에 Docker 설치하고 web 서버 이미지 실행하기

by developer's warehouse 2023. 11. 22.

이 글에서는 구글 클라우드의 기본 VM인 debian 계열 리눅스에 docker를 설치하는 방법 대해서 설명합니다. 

구글 클라우드 서버(GCP)에 Docker 설치하고 web 서버 실행하기 썸네일

구글 클라우드 서버에 docker 설치

다음 명령을 순차적으로 수행하면 설치가 완료됩니다. 

"이전 Docker 인스턴스 제거"와 "비 root 사용자로 Docker 실행"는 필요 시 수행하시면 됩니다.

# 이전 Docker 인스턴스 제거

sudo apt-get remove docker docker-engine docker.io containerd runc



# Docker CE를 위한 초기 패키지 설치

sudo apt-get update

sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release



# Docker CE GPG 키 추가

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg



# Docker CE APT 리포지토리에 추가

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null



# Docker CE 설치

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io



# Docker CE 설치 확인

sudo docker run hello-world



# 비 root 사용자로 Docker 실행

sudo groupadd docker

sudo usermod -aG docker $USER

newgrp docker 



web 서버 docker 이미지 실행하기

docker 설치 완료 후에 docker hub로 부터 이미지를 받아서 실행하기 위해서는 docker hub에 로그인을 해야 합니다. 

1. Docker에 로그인 하기 

sudo docker login을 통해 로그인을 합니다. sudo를 앞에 넣어주지 않으면 /var/run/docker.sock 파일에 대한 권한 문제로 로그인이 실패하는 것을 확인했습니다. 다. 

처음에 사용자 이름과 비밀번호를 물어보고 다음부터는 바로 로그인이 됩니다. 

 

2. Docker 이미지를 가져오기

Docker Hub에서 원하는 이미지를 찾아 docker pull 명령을 사용하여 이미지를 가져옵니다. 예를 들어, Ubuntu 이미지를 가져오려면 다음 명령을 사용합니다
아래는 제가 개인 docker hub에 올려놓은 웹 프로젝트를 이미지로 만들어 놓은 docker 이미지 입니다. 
sudo docker pull 이미지이름:태그

eeddyit0@instance-1:~$ sudo docker pull lswhh/myflask:v3.0
v3.0: Pulling from lswhh/myflask
7007490126ef: Pull complete 
1d60bfe7d569: Pull complete 
89b66eb40820: Pull complete 
4f4fb700ef54: Pull complete 
f5403cdde9e1: Pull complete 
4678f683a89b: Downloading [=>                                                 ]    339MB/8.734GB
7b5d670363e1: Downloading [======>                                            ]  362.6MB/2.964GB
b2a839aaa970: Download complete 
b01fda8b2cf3: Download complete 
491c4101ced8: Downloading [====================>                              ]  58.41MB/139.5MB

 

이미지 용량에 따라서 시간이 오래 걸릴 수 있습니다. 

eeddyit0@instance-1:~$ sudo docker images
REPOSITORY      TAG       IMAGE ID       CREATED       SIZE
lswhh/myflask   v3.0      ea4321c72a78   4 weeks ago   16.4GB

다운이 완료되면 웹 서비스 포트를 개방하여 이미지를 실행합니다. 

3. Docker 이미지 실행 

Docker 이미지를 실행하고, 호스트의 8000, 5000, 443, 80 포트를 컨테이너의 동일한 포트에 바인딩합니다. 그리고 /bin/bash를 실행하여 bash 셸에 진입합니다. <이미지 이름> 부분은 실행하려는 Docker 이미지의 이름으로 대체해야 합니다.

이미지마다 차이가 있는데 저의 경우 start.sh로 무한루프 도는 쉘을 만들어 놓았습니다. 

docker는 시작하면서 entrypoint에 해당하는 쉘을 수행하는데, 이 쉘이 종료되면 docker가 종료되기 때문에 웹 서비스의 경우 무한루프 도는 쉘을 넣어놓습니다. 

sudo docker run -d -p 8000:8000 -p 5000:5000 -p 443:443 -p 80:80 lswhh/myflask:v3.0 start.sh
위의 명령 수행 후 docker ps를 해보면 아래와 같습니다. docker ps를 수행 후 container id를 알아내서 docker exec -it [container id] bash 를 수행하면, 실행 중인 docker 이미지의 bash 쉘에 로그인 할 수 있습니다. 
 
eeddyit0@instance-1:~$ sudo docker ps -a
CONTAINER ID   IMAGE                COMMAND      CREATED         STATUS         PORTS                                                                                                                                                                      NAMES
2c898b2349b7   lswhh/myflask:v3.0   "start.sh"   8 seconds ago   Up 7 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 8090/tcp   silly_solomon
eeddyit0@instance-1:~$ sudo docker exec -it  2c898b2349b7 bash
root@2c898b2349b7:/home/eddy_lee# 

제 이미지의 경우 웹 서버를 자동으로 띄워주지 않도록 해 놓았으므로 bash로 로그인 해서 띄워 줘야 합니다. 

4. 웹 서비스 실행 및 방화벽 설정

docker 이미지에서 웹 서버를 시작하고 정상적으로 외부에서 접속되는지 확인합니다. 

기본적으로 구글 클라우드는 방화벽이 설정되어있어서 외부 접속이 되지 않습니다. 구글 클라우드 서버에서 방화벽 규칙을 추가하여 https:443 포트와 http:80 포트 등 사용하는 포트들을 열어줍니다. 

nginx의 설정 파일을 열어서 내용을 확인 후 ip부분으로 호스팅하는 것이 있으면 신규 구글 클라우드 서버의 ip로 변경해 줍니다.

 

vi /etc/nginx/sites-available/myflaskapp
root@2c898b2349b7:/home/eddy_lee# 
server {
    listen 80;
    server_name it.2story.org 34.64.235.86; #<-- ip 변경

    location / {

        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://localhost:8000;

    }
    proxy_connect_timeout       1200;
    proxy_send_timeout          1200;
    proxy_read_timeout          1200;
    send_timeout                1200;


}

IP를 변경 후에는 웹 서비스를 실행합니다. 이 부분은 제가 설정해 놓은 웹 서비스 실행 방식입니다. 

root@2c898b2349b7:/home/eddy_lee# . venv/bin/activate
(venv) root@2c898b2349b7:/home/eddy_lee# cat restart
cat: restart: No such file or directory
(venv) root@2c898b2349b7:/home/eddy_lee# cat restart.sh
cat: restart.sh: No such file or directory
(venv) root@2c898b2349b7:/home/eddy_lee# ls
flask  imgFilterApp  start.sh  venv
(venv) root@2c898b2349b7:/home/eddy_lee# cd flask/
(venv) root@2c898b2349b7:/home/eddy_lee/flask# cat restart.sh
bin/killport 8000
bin/gunicorn.start
sudo /etc/init.d/nginx restart
(venv) root@2c898b2349b7:/home/eddy_lee/flask# ps -ef |grep gunicorn
root         277      46  0 06:25 pts/0    00:00:00 grep --color=auto gunicorn
(venv) root@2c898b2349b7:/home/eddy_lee/flask# bin/gunicorn.start
(venv) root@2c898b2349b7:/home/eddy_lee/flask# tail -f error.log 
[2023-10-12 11:19:16 +0000] [4685] [INFO] Using worker: sync
[2023-10-12 11:19:16 +0000] [4687] [INFO] Booting worker with pid: 4687
[2023-10-12 11:19:16 +0000] [4688] [INFO] Booting worker with pid: 4688
SELECT qid, topic, situation, lquestion, rquestion, lvote_count, rvote_count FROM questions WHERE qid >= '1'
fetch
[2023-11-15 06:25:37 +0000] [283] [INFO] Starting gunicorn 20.1.0
[2023-11-15 06:25:37 +0000] [283] [INFO] Listening at: http://0.0.0.0:8000 (283)
[2023-11-15 06:25:37 +0000] [283] [INFO] Using worker: sync
[2023-11-15 06:25:37 +0000] [285] [INFO] Booting worker with pid: 285
[2023-11-15 06:25:37 +0000] [286] [INFO] Booting worker with pid: 286
^C
(venv) root@2c898b2349b7:/home/eddy_lee/flask# ps -ef |grep guni
root         283       1  0 06:25 ?        00:00:00 gunicorn: master [app:app]
root         285     283  8 06:25 ?        00:00:01 gunicorn: worker [app:app]
root         286     283  8 06:25 ?        00:00:01 gunicorn: worker [app:app]
root         293      46  0 06:25 pts/0    00:00:00 grep --color=auto guni
(venv) root@2c898b2349b7:/home/eddy_lee/flask# /etc/init.d/nginx restart
 * Restarting nginx nginx           

외부 웹 서버에서 nginx가 실행되어있는 구글 클라우드 서버의 IP로 접속해 보았을 때 접속이 되면 완료하면 됩니다. 

하지만, 접속이 안되는 경우 방화벽 문제인지 확인하기 위해서 local 에서 curl 명령으로 확인해 봅니다. 

 venv) root@2c898b2349b7:/home/eddy_lee/flask# curl -X GET localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<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/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

curl이 위와 같이 정상적으로 수행되는데 외부 접속이 안되는 경우가 있는데, 이 경우 새로 추가한 규칙의 우선순위를 확인해 보셔야 합니다. 

기본 우선순위보다 높은 우선순위로 설정해야 합니다. 기본 우선순위는 65535이며, 그 이하의 숫자값이 더 높은 우선순위가 됩니다. 즉, 낮은 값이 우선순위가 높은 것이 됩니다.

기타 오류가 발생하는 부분 수정: 현재 라이브러리 에러가 발생하여 일부 flask앱 실행이 안되었는데, 아래와 같이 라이브러리를 설치해 주니 문제없이 수행됩니다. 참고삼아 기록합니다. 

apt-get update

apt-get install libglib2.0-0

4. 인증서 갱신

docker 이미지에서 웹 서버를 시작하기 전에 https의 보안 인증서를 갱신해 줘야 합니다. 

보안 인증서는 3개월 마다 갱신해 줘야 합니다. 

certbot --nginx 명령을 수행하면 몇 가지 질문과 동의사항에 동의한 후 자동으로 nginx의 설정에서 인증서를 발급받을 수 있습니다. 

Which names would you like to activate HTTPS for?

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

1: ai.2story.org

2: it.2story.org

3: vs.2story.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Select the appropriate numbers separated by commas and/or spaces, or leave input

blank to select all options shown (Enter 'c' to cancel): 

Obtaining a new certificate

Performing the following challenges:
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
Future versions of Certbot will automatically configure the webserver so that all requests redirect to secure HTTPS access. You can control this behavior and disable this warning with the --redirect and --no-redirect flags.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://ai.2story.org,
https://it.2story.org, and https://vs.2story.org

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=ai.2story.org
https://www.ssllabs.com/ssltest/analyze.html?d=it.2story.org
https://www.ssllabs.com/ssltest/analyze.html?d=vs.2story.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/ai.2story.org/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/ai.2story.org/privkey.pem
   Your cert will expire on 2024-02-13. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

 

 

facebook twitter kakaoTalk kakaostory naver band shareLink