일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 개발 영어실력
- 데이터베이스
- 실무PT
- 개발실무
- tableplus
- 컴공과개념정리
- 개발 공식문서 읽기
- 데이터스키마
- 알고리즘
- postgredb
- golang
- 자료구조
- 웹서버
- jsx
- 스키마모델
- 자바
- 코딩강의
- HTTP
- 파이썬
- Go언어
- 유데미
- 코멘토
- 코멘토실무PT
- 개발 공식문서
- 리액트
- 개발자되기
- 개발공부
- Go언어실무
- 개발공식문서 어려움
- 개발자공통지식
- Today
- Total
웹개발일지
Docker 활용 웹 어플리케이션 배포 본문
이 글은 코멘토에서 1달간 Go언어 서버 개발과정 실무 PT를 실시간으로 수강한 후기와 4주차 수업내용인 Docker로 웹애플리케이션을 실행하는 과정을 담았습니다.
오늘은 그동안 Go언어로 웹서버를 구현하고 구현한 서버를 게시판 형태의 클라이언트에 연결하고 마지막으로 그 작업들을 도커 환경에서 실행해보는 작업을 했다.
도커의 배포 과정이 어떻게 되는 것인지 수업 시작전 대략 찾아보았다. 도커라는 것이 가상의 별도 실행환경이어서 그런지 별도의 명령어가 있었다. 수업이 3시간이라 굉장히 알차지만 그만큼 속도도 빠르게 진행되기 때문에 예습한 덕분인지 마지막 수업을 보다 수월하게 따라갈 수 있었다. 하지만 굉장히 반복되는 오류 이슈들이 있었고 수업 중간중간 강사님께서 잘 봐주신 덕분에 실습을 하면서 마무리 할 수 있었다.
사실 실시간 강의를 장시간 듣다보면 코드를 그냥 따라치게 되는 경우가 발생하는데 그러지 않을 수 있도록 강사님께서 중요한 개념을 잘 짚어주시고, 코드 오류를 해결하는 것 보다 당장 중요한 개념을 이해하고 가는것에 시간을 들여주셔서 감사하며 마무리할 수 있었다.
복습, 도커란?
리소스를 격리한 기술이다. 프로세스간 격리는 default인데 컨테이너로 실행하고 관리가 들어간다. 소프트웨어 실행에 필요한 모든 것을 완전한 파일형태로 감싸는 형태이다. 다음과 같은 경우이다. golang의 os 사용코드가 usr > go 실행파일 안에 fmt 파일이 설치되어있지 않으면 해당 코드를 사용할 수 없는 것 처럼 파일들이 다 존재해야한다는 거다. 심지어 shell까지 포함한다. 그래서 뒤에서 나오지만 port도 별도로 주어야하고 실행환경을 별도로 실행시켜두어야 그 안에서 터미널 동작이 가능하다. 새로운 실행환경에 진입하는 형태.
이는 실행 환경(윈도/.맥/리눅스)에 관계없이 언제나 동일하게 실행될 것을 보장한다. 또, 컨테이너 안에서 실행하는 것이기 때문에 컨테이너 밖에 별도로 loc4al이 존재한다고 생각하면 된다.
도커의 이미지란 무엇일까?
이미지라고 해서 정말 이미지 파일 형태의 무언가를 말하는 것인가 했다. 이미지라는 것은 컨테이너 생성지침을 기술한 읽기 전용 템플릿이다. 자유롭게 다운로드하며 사용이 가능하다. 예를들면 우분투 기반으로 하는 이미지를 빌드하지만 아파치기반 웹 서버와 응용프로그램을 설치하고 실행하는데 필요한 것들을 설치할 수 있다. 도커 파일의 각 명령은 이미지에 계층을 생성한다. maria db이미지면 mariadb 계층. 도커 파일을 변경하고 이미지를 재구성하면 변경된 계층만 구성된다. 다른 가상화 기술과 비교했을 때 이미지를 매우 가볍고 작고 빠르게 만들 수 있는 부분이다. 개념이 잘 와닿지 않을 수 있다. 실습을 하면서 보다 명확하게 잡을 수 있다.
도커의 컨테이너란 무엇일까?
컨테이너는 이미지를 포함한 하나의 애플리케이션이다. 이미지 단위를 기반으로 실제 실행을 담당한다. 이미지를 재생성한다는 개념도 있는데 여기서 재생성한다는 것은 기존 상태에 덧붙이는 방식이라 maria db를 설치하고 재생성하면 그 상태로 새로 씌워지며 생성되는 것이다. 컨테이너는 도커 API, CLI 사용을 통해 컨테이너를 생성, 시작, 중단, 이동 혹은 삭제할 수 있다.
주요 Objects
여기서 도커 데몬은 도커 API요청을 수신하고 이미지,컨테이너, 네트워크 및 볼륨과 같은 도커 개체들을 관리한다. 데몬은 도커 서비스를 관리하기 위해 다른 데몬과 통신할 수도 있다.
레지스트리는 이미지를 관리하는 저장소이다. 도커 명령어들은 이 객체들을 관리하는 역할을 한다. 실습을하면서 도커 데몬 어쩌구하는 오류가 많이 났었다.
중간 질문이 있었다. 도커를 왜 사용할까에 대한 의문이었다. 압축파일같은 것 받아서 대충 실행환경을 맞추면 되는데 왜 굳이 도커를 써야하나, 만약 서버가 하나 있는데 요청을 너무 많이 받아 cpu를 많이 잡아먹는 상황이다. 이렇게 프로그램이 정상적이지 못할경우 대비해서 VM이라는 게 나왔다. VM은 윈도우에 맥이 필요해서 가상으로 설치할 수 있는 일종의 그런 가상 환경이다. 결론은 프로그램마다 서버를 설치하기엔 리소스가 너무 드니까 VM을 만들어서 리소스를 줄이기 위함이었다. 그리고 나온것이 컨테이너란 개념이다. 컨테이너는 os 같은 경우에도 컨테이너 내부에 이미지 파일로 다 포함해서 os를 따로 설치할 필요가 없이 컨테이너가 이미지 형태로 모두 가지고있기 때문에 보다 편리하게 서버를 사용할 수 있게된 것이다.
ngine x
웹서버이다. 다른웹서버로 넘어가는 역할을 해준다 (proxy역할)
8080:80의 80은 도커 컨테이너의 포트이다. docker run ~nginx 명령시 도커 엔진을 찾게된다.
도커 명령어들
docker run
도커run은 도커 컨테이너를 실행시키는 명령어이다. 별도의 파일시스템으로 동작하며 별도 운영체제를 갖는다. 아얘 다른, 독립된 환경에 들어가게 되는 것이다.
docker ps
실행중인 도커 이미지들과 도커 컨테이너 id를 확인할 수 있다. 다만 정지되지 않은 컨테이너만 나타낸다
이렇게 컨테이너 ID, Image, Command, Created로 구성되어 나온다.
docker rm containerid
해당 id의 컨테이너를 삭제한다. 지운다음 id를 반환한다. docker ps를 다시 출력해보면 해당 컨테이너 id로 존재했던 것이 없어졌음을 확인할 수 있다.
docker run -d -p 8080:80 engine
원래 실행환경으로 돌아온다. docker ps를 보면 컨테이너는 실행중인 것을 알 수 있다. 보통은 컨테이너 안에 들어가서 작업할 일이 없으니 이 명령어로 실행을 한다. 아래 실습할 명령어들도 다 이 명령어로 실행했다.
docker log
연결에 문제가있거나 할 시 로그를 살펴볼 수 있다.
docker inspect
ip주소등 도커 실행환경에 대한 모든 정보가 나온다. ip주소, gateway, port 등 확인 가능하다.
게이트웨이
도커 정보중 netapi와 net mask 라는 용어가 있어 부연설명을 들었다. 네트워크를 찾아가는 방식을 게이트웨이한테 물어보게 되는데. 게이트웨이는 ip주소들을 관리하고 있다. 그래서 게이트웨이한테 171.xx.~~를 찾아달라고 하면 게이트웨이가 ip를 찾아주는데 여기서, 해당 게이트웨이에 속한 ip인지 확인하기 위한 것이 netmask 이고 여기서 숫자가 끝까지 일치하면 ip가 있다는 뜻이다.
docker images
도커 이미지들 출력이 가능하다.
이미지 출력시 나오는 none은 예전 이미지에 덮어씌워진 경우인건데 캐시에 저장된 임시데이터인 것이다. 이미지에서는 이런 데이터들이 꽤 생긴다. 지울 수도있다. docker image prune을 하면 캐시된임시 이미지들을 정리한다. docker image prune -a 는 모두 다 지워버린다.
docker inspect imageID
- Inspect options
- --format, -f
- --size, -s
- --type
뒤에 옵션을 붙여 해당 id 이미지가 있는지 조회한다.
docker $(docker ps -aq)
이미지 id들을 출력한다
docker rm -f $(docker ps -aq)
도커 컨테이너를 지운다
docker rmi nginx
도커 이미지를 지운다.
- https://docs.docker.com/engine/reference/run
- https://docs.docker.com/engine/reference/commandline/ps
- https://docs.docker.com/engine/reference/commandline/build
- https://docs.docker.com/engine/reference/commandline/images
- https://docs.docker.com/engine/reference/commandline/rm
- https://docs.docker.com/engine/reference/commandline/rmi
docker rmi
docker rmi: Removes (and un-tags) one or more images from the host node. If an image has multiple tags, using this command with the tag as a parameter only removes...
docs.docker.com
이미지 만들기
3주차 때 만들어둔 웹 게시판의 백엔드 파일에 들어가 이미지를 만들어 줄 것이다. 이 때 백엔드의 서버는 도커가 run 상태여야 실행이 가능하다.
docker run -d -p 3306:3306 --name some-mariadb --env MARIADB_USER=user --env MARIADB_PASSWORD=password --env MARIADB_ROOT_PASSWORD=password --env MARIADB_DATABASE=dev mariadb:latest
- env: 환경변수 설정
- 도커 컨테이너 내부에 다 세팅이 되어있기 때문에 환경변수 세팅만해서 db를 바로 사용 가능하다. 여기서 conflict 됐다는 오류가 발생했는데 내 도커 포트가 3307번인것을 적용해주지 않아서였다. run -d -p 뒤 포트번호를 3307로 수정하여 다시 실행하였다.
Dockerfile
touch Dockerfile
도커파일은 별도의 파일 확장자 필요없는 단순 텍스트기반 파일이다. 컨테이너 이미지를 생성하기 위해서는 도커파일이 필요하다. 위는 도커 파일을 만들어주는 명령이다. 만들어줄 위치에서 해당 명령어를 실행한다.
docker build -t getting-started .
이미지를 생성하는 명령어이다.
FROM golang:1.18-alpine
WORKDIR /app
# 도커파일의 위치가 됨(호스트)
COPY . ./
# go.mod 의 파일들을 컨테이너 내부로 다운로드 시키는 작업임
RUN go mod download
# 바이너리 생성 ; -o는 파일이름
RUN go build -o /server
EXPOSE 8081
CMD ["/server"]
- alpine: 가벼운 os
- working directory 설정. 현재 경로 아래 app으로 경로 설정해준다.
- Copy : 이미지는 도커파일로 만들어야한다. 여기가 이미지에 대한 명세가 있는 것이다. 코드를 다 수행해서 이미지에 말아넣는 것이다. 이미지는 컨테이너를 위한 모든 프로그램을 담고있어야한다. 그걸 host에서 넣어주는 것이다. 호스트가 이미지를 빌드한다. 필요한 의존성들을 도커파일에 명세하고 이미지를 빌드 하는 컴퓨터에서 소스를 읽어다가 필요한 것을 파악해서 이미지에 빌드시킨다. 이 작업은 도커를 사용하지 않고 go 를 처음 install 했을때 go.mod 파일을 만들고 go.mod tidy를 했던 작업을 한꺼번에 수행하는 것과 동일하다. /app/ go-server 아래 파일들이 여기로 copy된 것이라고 보면 된다.
클라이언트는 끄지 않고 서버에서 docker images를 실행하여 확인한다. 여기서 도커 빌드가 안됐었는데 이미지 태그 뒤에 경로를 지정해주지않아서 다음과 같은 오류가 났었다. "unable to find image"
잠시 프로젝트의 main.go 파일을 보자, 메인에서 데이터베이스에 연결하는 코드가있다. 바로 아래 부분인데,
dbHandler, err := db.NewAndConnectGorm("user:password@tcp(172.17.0.2:3307)/dev?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
fmt.Printf("%+v\n", err)
}
tcp 뒷부분의 (127.17.0.2:3307) 즉 도커의 포트로 바꿔준 모습이다. 원래는 로컬호스트 포트를 갖고있었다. 되게 중요한 부분인데 서버 컨테이너가 있고 호스팅 머신이 있으면 maridb 컨테이너가 호스트의 3306과 연결되어있다. 서버가 컨테이너로 안뜨고 로컬에서 뜰때는 자기자신의 ip(127.0.01) 3306으로 가능했는데 현재는 도커 컨테이너에서 실행중이기 때문에 아무것도 리슨하고 있는 서버가 없다는것이다. 컨테이너에서 3306에 연결하려고 하면 연결되지 않는다. 이런경우 연결이 되지 않기때문에 위 주소를 도커 컨테이너의 포트로 바꿔준것이다. 컨테이너 포트 조회는 docker inspect를 통해 볼 수 있다.
docker network ls
도커 기본 네트워크는 브릿지이다. 추가개념으로 드라이버 동작방식, 호스트네트워크, 브릿지 네트워크 등을 살펴볼 수 있다.
브릿지의 사용이유는 바로 위의 상황처럼 도커의 애플리케이션이 호스트에서와 다른 네트워크로 동작하기 때문에 포트 연결을 위해 징검다리 역할을 하는 것이다.
클라이언트를 도커로 실행하기
주요개념
- CORS(cross - origin requests)
- proxy 서버, fetch
CORS
개념이 새롭다보니 직역을 하게 된다. 교차 Origin 리소스 공유방식이라고 하는 교차 출처 방식, CORS는 브라우저가 허용해야하는 자체 소스 이외의 모든 Origin(도메인, 스키마, 포트)을 나타낼 수 있도록하는 HTTP 기반 메커니즘이다. 개념이 잘 와닿지 않는데, 실습을 진행해보니 리퀘스트를 보낼때 뭔가 잘못보내서 발생하는 오류 같았다. 이를 방지하기 위한 코드를 짜야한다. 여기서 알아야하는건 Same Origin 과 Cross Origin 정책인데 이 정책들에 위배해서 리퀘를 보낼때 CORS 에러가 나는 것이라고 한다. 출처라는 것이 엇갈린 다른 출처를 뜻한다고 한다.
Origin : 프로토콜 + 호스트 + 포트 를 합친 URL 을 뜻함.
이렇게 4주간의 Go언어 실무PT 가 완성되었다. 강의를 들으며 가장 좋았던 점은 이해가 어려운 부분들을 1:1 로 수업외 시간에 질문 할 수 있다는 점이었다. 1주차때 기대하던 점이 이 강의를 마치고 나면 웹서버 구동 방식에 전반적인 흐름을 이해하고 각 프레임워크들을 활용해보는 것이었다. 이번 실무 PT참여를 통해 앞서 말한 점을 달성한 것 같아 뿌듯한 한달을 보낸 것 같고 또 혼자 공부하는 입장에서 공부를 어떻게 이어나가면 되는지 흐름을 갖게되어서 좋은 것 같다. 2주차부터 다뤘던 내용이 처음 해보는 것들이라 이해가 쉽진 않았는데 질문도 많이하고 복습강의도 여러번 돌려보면서 목표했던 바를 갖게된 것 같다.
성과를 만드는 현직자의 실무 노하우 ㅣ 코멘토
내 실무에 적용하며 성과내는, 진짜 실무 퍼스널 트레이닝!
comento.kr
'Lang > Go' 카테고리의 다른 글
Go언어의 동시성 프로그래밍, 고루틴 (0) | 2023.08.29 |
---|---|
CRUD 게시판 웹서버 구현 (0) | 2023.01.06 |
Go Scan() 함수의 기본과 활용 (0) | 2023.01.05 |
Go 자료구조 : map [맵] (0) | 2022.12.24 |
Golang 기본 문법 복습 및 Mutex 패키지 활용 (3) | 2022.12.20 |