-
노노그램 서버 제작기 3: 노트북에 서버 구축하기Programming/Projects 2024. 9. 14. 18:44
도커로 빌드한 서버를 실제 배포하고 운영하는 과정을 다룹니다.
원격 도커 배포 설정부터 DuckDNS를 활용한 도메인 연결, SWAG를 이용한 Nginx 리버스 프록시 구성과 SSL 인증서 설정등의 내용을 포함하고 있습니다.Intro
이번에는 집에 남는 노트북에 서버를 올려 구동까지 해보겠습니다.
이전에 쓰던 노트북이 힌지 부분이 완전히 박살나서 잘못 열면 모니터도 같이 와사삭 부셔지는 그런 상태인데요.
나름 성능 자체는 괜찮아서 이참에 이 친구를 저전력 모드로 돌리면서 서버 컴퓨터로 쓰려고 했습니다.OS는 원래 깔려 있던 윈도우를 밀고 우분투를 깔아 주었고요.
Tailscale을 통해 어디서든 원격 연결 할 수 있도록 설정해주었습니다.원격 연결에 대해서는 이전에 쓴 글 [[SSH로 원격 서버 안전하게 접속 관리하기]] 를 참조해 주시고요.
그 외 자동 완성을 위한 zsh와 도커 데스크탑 정도를 설치 해 주었습니다.원격 배포하기
services: app: build: . ports: - 8080:8080 depends_on: db: condition: service_healthy environment: - DB_HOST=db - DB_USER=pz_admin - DB_PASSWORD=${DB_PASSWORD} - DB_NAME=puzzle_db - DB_PORT=5432 db: image: postgres:14 restart: always healthcheck: test: ["CMD", "pg_isready"] interval: 10s timeout: 5s retries: 5 volumes: - ./puzzle_db_dump.sql:/docker-entrypoint-initdb.d/puzzle_db_dump.sql - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USER=pz_admin - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=puzzle_db - POSTGRES_PORT=5432 volumes: pgdata:
저번에 작성했던
docker-compose.yml
파일입니다.How to Deploy on Remote Docker Hosts with Docker Compose
DOCKER_HOST
를 명시하면 컴포즈 파일로 간단하게 원격 배포가 가능하다고 합니다.DOCKER_HOST="ssh://brokenhinge@dev-machine" docker-compose up -d
실행했는데 퍼즐을 제대로 못 가져옵니다.
curl localhost:8080/puzzles failed to fetch puzzle
docker logs nonogram-terminal-server-db-1
으로 로그를 확인해 보니 다음 문제가 있었습니다.psql:/docker-entrypoint-initdb.d/puzzle_db_dump.sql: error: could not read from input file: Is a directory
컴포즈 파일의 다음 라인에 문제가 있던 것 같습니다.
./puzzle_db_dump.sql:/docker-entrypoint-initdb.d/puzzle_db_dump.sql
찾아보니이렇게 bind mount를 사용할 경우 호스트 환경에서
puzzle_db_dump.sql
파일을 찾는다고 합니다.
서버 PC에서 파일을 찾고 있는 거죠.파일을 따로 전달해주는 건 귀찮으니, 데이터베이스용 따로 작성해서 이미지 빌드 과정에서 파일을 넣어 주겠습니다.
# syntax=docker/dockerfile:1 FROM postgres:14 COPY ./db_scripts /docker-entrypoint-initdb.d/
services: app: build: ./app ports: - 8080:8080 depends_on: db: condition: service_healthy environment: - DB_HOST=db - DB_USER=pz_admin - DB_PASSWORD=${DB_PASSWORD} - DB_NAME=puzzle_db - DB_PORT=5432 db: build: ./postgres restart: always healthcheck: test: ["CMD", "pg_isready"] interval: 10s timeout: 5s retries: 5 volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USER=pz_admin - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=puzzle_db - POSTGRES_PORT=5432 volumes: pgdata:
이제 정상 작동 하네요.
curl localhost:8080/puzzles {"id":817,"title":"고스트 앤 다크니스","author":"soyosun","row_size":20,"col_size":20,"clues":{"col_clues":[[3,5],[3,5,4],[2,12],[3,13,1],[3,12,1],[17,2],[5,12],[4,1,11],[2,2,11],[2,2,2,7],[2,2,1,5],[2,2,7],[3,3,1,4],[3,2,2,5],[3,4,4],[2,3,2,2,4],[2,2,2,7],[3,1,4],[2,3,5],[2,10]],"row_clues":[[8,3],[15],[5,3,2],[6,1,2],[1,2],[1,3,4,3],[2,3,4,2,1],[6,2,1,1],[1,5,1,1,1],[9,5,2],[11,3,2],[9,1,1],[9,3,2],[10,3,2,2],[1,8,1,1,2],[10,2,4],[19],[3,12,1],[2,13,1],[1,11,2]]}}
서버 열기
프로그램 배포가 되었으니 본격적인 서버 셀프 호스팅을 시작해줍니다.
아래 가이드를 거의 그대로 따라했는데요.
Easy Free and Secure Self-Hosting at Home가정용 인터넷이라 IP 고정이 안되기 때문에 DDNS가 필요한데, DuckDNS를 사용해 DDNS 서비스 및 무료 도메인, SSL 인증까지 해결할 수 있었습니다.
웹 서버로는 SWAG을 사용했습니다.
Nginx를 기반으로 설정하기 편하게 되어 있어서 초기 단계에서 사용하기 좋을 것 같았습니다.기초 설정 템플릿이 잘 나와 있어서 이를 기반으로
nonogram.subfolder.conf
파일을 아래와 같이 작성 해 주었습니다.location /nonogram { return 301 $scheme://$host/nonogram/; } location ^~ /nonogram/ { include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app nonogram-terminal-server-app-1; set $upstream_port 8080; set $upstream_proto http; rewrite ^/nonogram/(.*) /$1 break; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } ``` 도커 네트워크를 연결 해주었습니다. ```bash docker network connect nonogram-terminal-server_default swag
ssl 인증이 안되어서 https 접속이 불가능한 이슈가 생겼습니다.
SWAG Documentation 을 보니 DuckDNS의 한계로 인해 wildcard subdomain(*.dvbeetle.duckdns.org
) 에 대한 인증서가 main url(dvbeetle.duckdns.org
) 까지 적용되지 않는다고 합니다.그래서 아예 서버 차원에서 서브 도메인 없이 접속 한 경우
www.
로 접속하도록 리디렉션을 걸어버리기로 했습니다.# redirect all traffic to https server { listen 80 default_server; listen [::]:80 default_server; location / { return 301 https://www.$host$request_uri; } } # WWW redirection server { listen 443 ssl; listen [::]:443 ssl; server_name dvbeetle.duckdns.org; return 301 https://www.$host$request_uri; } # main server block server { listen 443 ssl default_server; listen [::]:443 default_server; server_name www.dvbeetle.duckdns.org; # ... }
테스트 해보기
뭔가 서버 테스트를 해보고 싶습니다. 근데 어떻게 해야될 지 잘 모르겠네요.
그냥 요청이라도 무작정 많이 보내보고 싶어서 wrk라는 걸 찾아서 써보기로 했습니다.wrk -t2 -c10 -d30s https://www.dvbeetle.duckdns.org/nonogram/puzzles Running 30s test @ https://www.dvbeetle.duckdns.org/nonogram/puzzles 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 7.50ms 9.80ms 225.65ms 98.79% Req/Sec 735.93 71.28 0.87k 82.64% 43944 requests in 30.03s, 32.99MB read Non-2xx or 3xx responses: 8 Requests/sec: 1463.15 Transfer/sec: 1.10MB
데이터베이스 연결 수를 제한해둬서 서버가 느려질 수 는 있겠습니다만, "Non-2xx or 3xx responses" 는 조금 수상합니다.
Wireshark로 확인해보니 서버에서 랜덤 row를 못찾았다고 응답하는 경우가 8회 있었습니다.
이게 로컬 환경에서도 그런지, 파이썬으로 서버가 아닌 DB에 직접 요청을 잔뜩 보내서 확인을 해 보기로 했습니다.
몇 천번에 한 번 꼴로TABLESAMPLE BERNOULLI(1)
이 실패하는 듯 보였습니다.
레코드 수가 100개가 넘어서 상관 없을 줄 알았는데요. 그런 원리는 아니였나 봅니다.2%로 늘리니 10만번 요청해도 실패 하는 경우가 없었습니다.
Outro
다음 편은 아마 서버 api를 좀 더 확장해보는 내용이 되지 않을까 싶습니다.
클라이언트도 필요한데, C로 되어있는 클라이언트를 쭉 유지보수 할 지, 아니면 더 생산성이 높은 언어로 바꿀 지도 고민이 됩니다.
3편이 마지막이 되지 않았으면 좋겠는데, 다음 편은 아무래도 시간이 조금 걸릴 것 같네요 ㅎㅎ.