Skip to content

Commit

Permalink
Update chapter16
Browse files Browse the repository at this point in the history
  • Loading branch information
gleaming9 committed Nov 13, 2024
1 parent d907b85 commit 6d6b9b5
Show file tree
Hide file tree
Showing 71 changed files with 1,900 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN go mod download

#전체 소스 파일을 /app으로 복사하고 최적화된 바이너리 생성
COPY . .
RUN go build -trimmpath -ldflags="-w -s" -o app
RUN go build -trimpath -ldflags="-w -s" -o app

# 최종 배포 단계 : 실제 운영 환경에서 실행될 최소한의 이미지 생성
#경량화된 Degian 이미지 사용
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

DOCKER_TAG := latest
build: ## Build the docker image
docker build -t gleaming9/go_todo_app:${DOCKER_TAG} --target deploy ./
docker build -t gleaming9/go_todo_app:${DOCKER_TAG} \
--target deploy ./

build-local: ## Build the docker image for local development
docker compose build --no-cache
Expand Down
2 changes: 1 addition & 1 deletion _chapter15/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN go mod download

#전체 소스 파일을 /app으로 복사하고 최적화된 바이너리 생성
COPY . .
RUN go build -trimmpath -ldflags="-w -s" -o app
RUN go build -trimpath -ldflags="-w -s" -o app

# 최종 배포 단계 : 실제 운영 환경에서 실행될 최소한의 이미지 생성
#경량화된 Degian 이미지 사용
Expand Down
43 changes: 43 additions & 0 deletions _chapter16/section60/.air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
root = '.'
tmp_dir = 'tmp'

[build]
cmd = "go build -o ./tmp/main ." #Go 프로젝트를 빌드
bin = "./tmp/main" #빌드된 실행 파일 경로
#실행 파일 실행 시 필요한 환경 변수와 인자 설정 -> 80번 포트 사용하도록 인수 지정
full_bin = "APP_ENV=dev APP_USER = air ./tmp/main 80"

# 파일 변경 감지 설정 -> 변경을 감지할 파일 확장자
include_ext = ["go", "tpl", "tmpl", "html"]
# 감지하지 않을 디렉터리 목록
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules", "_tools", "cert", "testutil"]
include_dir = []
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = true
exclude_underscore = false
follow_symlink = false

#로깅 설정 : 로그파일 경로, 파일 변경 감지 후 재빌드 대기 시간
log = "air.log"
delay = 1000

#오류 처리 설정
stop_on_error = true
send_interrupt = false
kill_delay = 500

[log]
time = false

[color]
#로그 출력 시 사용할 색상 설정
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

#프로그램 종료 시 임시 디렉터리 삭제 여부
[misc]
clean_on_exit = true

2 changes: 2 additions & 0 deletions _chapter16/section60/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.git
.DS_Store
43 changes: 43 additions & 0 deletions _chapter16/section60/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#최종 배포할 실행 파일 만드는 과정
#multi-stage build에서 이 단계의 이름을 'deploy-builder'로 지정
FROM golang:1.23.1-bullseye AS deploy-builder

#app 디렉토리 생성 및 작업 디렉토리로 설정
WORKDIR /app

#종속성 파일(go.mod go.sum)만 복사해서 캐시 활용
#소스코드가 변경되어도 종속성이 변경되지 않았다면 도커의 캐시 활용
COPY go.mod go.sum ./
#프로젝트의 모든 종속성 다운로드
RUN go mod download

#전체 소스 파일을 /app으로 복사하고 최적화된 바이너리 생성
COPY . .
RUN go build -trimpath -ldflags="-w -s" -o app

# 최종 배포 단계 : 실제 운영 환경에서 실행될 최소한의 이미지 생성
#경량화된 Degian 이미지 사용
FROM debian:bullseye-slim AS deploy

#시스템 패키지 최신화
RUN apt-get update

#첫 번째 단계에서 만든 실행 파일만 복사
COPY --from=deploy-builder /app/app .

#컨테이너 시작 시 애플리케이션 자동 실행
CMD ["./app"]

#개발자의 로컬 환경을 위한 설정
FROM golang:1.23 AS dev

#/app 디렉토리를 작업공간으로 설정
WORKDIR /app

#air 도구 설치 (코드 변경 시 자동 재빌드 지원)
RUN go install github.com/air-verse/air@latest

#개발 서버 자동 시작
CMD ["air"]

## docker-compose down -v <= 실행중인 컨테이너를 멈추고 매핑된 볼륨들을 제거
29 changes: 29 additions & 0 deletions _chapter16/section60/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.PHONY: help build build-local up down logs ps test
.DEFAULT_GOAL := help

DOCKER_TAG := latest
build: ## Build the docker image
docker build -t gleaming9/go_todo_app:${DOCKER_TAG} \
--target deploy ./

build-local: ## Build the docker image for local development
docker compose build --no-cache

up: ## 자동 새로고침을 사용한 도커 컴포즈 실행
docker compose up -d

down: ## 도커 컴포즈 종료
docker compose down

logs: ## 도커 컴포즈 로그 출력
docker compose logs -f

ps: ## 실행중인 컨테이너 확인
docker compose ps

test: ## 테스트 실행
go test -race -shuffle=on ./...

help: ## 옵션 보기
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
28 changes: 28 additions & 0 deletions _chapter16/section60/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:

# 'app'이라는 이름의 서비스(컨테이너)를 정의
app:
# 사용할 Docker 이미지 이름 : 'gotodo'
image: gotodo

build:
#빌드할 파일들이 있는 위치를 지정 : .. <- 한칸 위 폴더에 go.mod 위치
#go_todo_app 폴더를 컨텍스트로 설정
context: .
dockerfile: Dockerfile
# target=dev로 설정하여 Dockerfile의 dev stage를 빌드
args:
target: dev
environment: # 환경 변수 설정
TODO_ENV: dev
PORT: 8080

# 로컬 컴퓨터의 파일과 컨테이너 안의 파일을 연결, 코드 수정 시 바로 컨테이너에 반영
volumes:
- .:/app # go_todo_app 루트 디렉터리를 컨테이너의 /app에 마운트

# 컨테이너가 사용할 포트를 지정
ports:
# 웹 브라우저에서 localhost:18000으로 접속하면 컨테이너의 80번 포트로 연결
# 왼쪽은 내 컴퓨터의 포트, 오른쪽은 컨테이너 안의 포트
- "18000:8080"
8 changes: 8 additions & 0 deletions _chapter16/section60/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module go_todo_app

go 1.23.1

require (
github.com/caarlos0/env/v6 v6.10.1 // indirect
golang.org/x/sync v0.9.0 // indirect
)
2 changes: 2 additions & 0 deletions _chapter16/section60/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
58 changes: 58 additions & 0 deletions _chapter16/section60/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package section60

import (
"context"
"fmt"
"go_todo_app/config"
"golang.org/x/sync/errgroup"
"log"
"net"
"net/http"
"os"
)

// (-) func run (ctx context.Context, l net.Listener) error{
func run(ctx context.Context) error {
cfg, err := config.New()
if err != nil {
return err
}

l, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.Port))
if err != nil {
log.Fatalf("failed to listen port %d: %v", cfg.Port, err)
}
url := fmt.Sprintf("http://%s", l.Addr().String())
log.Printf("start with: %v", url)

s := &http.Server{
// 인수로 받은 net.Listener를 이용하므로 Addr 필드는 지정하지 않습니다.
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}),
}
eg, ctx := errgroup.WithContext(ctx)
eg.Go(func() error {
// Serve 메서드로 변경합니다.
if err := s.Serve(l); err != nil &&
err != http.ErrServerClosed {
log.Printf("failed to close: %+v", err)
return err
}
return nil
})

<-ctx.Done()
if err := s.Shutdown(context.Background()); err != nil {
log.Printf("failed to shutdown: %+v", err)
}

return eg.Wait()
}

func main() {
if err := run(context.Background()); err != nil {
log.Printf("failed to terminate server: %v", err)
os.Exit(1)
}
}
56 changes: 56 additions & 0 deletions _chapter16/section60/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package section60

import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
"io"
"net"
"net/http"
"testing"
)

func TestRun(t *testing.T) {
// TestRun 함수의 컴파일 오류를 해결하기 위해 일단 t.Skip 함수를 사용합니다.
t.Skip("리펙토링 중")

// net/http 에서는 포트 번호에 0을 지정하면 사용 가능한 포트 번호를 동적으로 선택합니다.
l, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatalf("failed to listen port %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
eg, ctx := errgroup.WithContext(ctx)
eg.Go(func() error {
return run(ctx, l)
})

in := "message"
url := fmt.Sprintf("http://%s/%s", l.Addr().String(), in)
// 어떤 포트 번호로 리슨중인지 확인합니다.
t.Logf("try request to %q", url)
rsp, err := http.Get(url)

// 이후 코드 동일
if err != nil {
t.Errorf("failed to get: %+v", err)
}
defer rsp.Body.Close()

got, err := io.ReadAll(rsp.Body)
if err != nil {
t.Fatalf("failed to read body: %v", err)
}

// HTTP 서버의 반환값을 검증합니다.
want := fmt.Sprintf("Hello, %s!", in)
if string(got) != want {
t.Errorf("want %q, but got %q", want, got)
}

// run 함수를 종료합니다.
cancel()
if err := eg.Wait(); err != nil {
t.Fatal(err)
}
}
43 changes: 43 additions & 0 deletions _chapter16/section61/.air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
root = '.'
tmp_dir = 'tmp'

[build]
cmd = "go build -o ./tmp/main ." #Go 프로젝트를 빌드
bin = "./tmp/main" #빌드된 실행 파일 경로
#실행 파일 실행 시 필요한 환경 변수와 인자 설정 -> 80번 포트 사용하도록 인수 지정
full_bin = "APP_ENV=dev APP_USER = air ./tmp/main 80"

# 파일 변경 감지 설정 -> 변경을 감지할 파일 확장자
include_ext = ["go", "tpl", "tmpl", "html"]
# 감지하지 않을 디렉터리 목록
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules", "_tools", "cert", "testutil"]
include_dir = []
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = true
exclude_underscore = false
follow_symlink = false

#로깅 설정 : 로그파일 경로, 파일 변경 감지 후 재빌드 대기 시간
log = "air.log"
delay = 1000

#오류 처리 설정
stop_on_error = true
send_interrupt = false
kill_delay = 500

[log]
time = false

[color]
#로그 출력 시 사용할 색상 설정
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

#프로그램 종료 시 임시 디렉터리 삭제 여부
[misc]
clean_on_exit = true

2 changes: 2 additions & 0 deletions _chapter16/section61/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.git
.DS_Store
Loading

0 comments on commit 6d6b9b5

Please sign in to comment.