✔️ Golang
https://go.dev/doc/tutorial/getting-started
✔️ Golang 특징
- Golang은 고속의 퍼포먼스를 내야하는 프로그램을 만들 때 사용한다.
- Go의 가장 큰 특징은 병렬처리가 매우 쉽다는 것이다.
병렬처리를 위해서는 2개 이상의 프로세스의 동기화라는 챌린지가 있다.
Go는 고루틴을 통해 오버헤드가 거의 없는 병렬 처리 로직을 간단한 문법으로 구현할 수 있다. - Go는 pointer가 있다.
- 컴파일 언어지만 컴파일 속도가 매우 빠르다는 장점이 있다.
c언어는 gcc를 이용해서 실행 파일을 만들지만 go는 실행 파일을 만들지 않고 script 언어처럼 작동한다.
✔️ Golang App 개발 환경 준비
(djangoapp) vagrant@docker ~/golang/hello mkdir golang
(djangoapp) vagrant@docker ~/golang/hello cd golang
(djangoapp) vagrant@docker ~/golang/hello mkdir hello
(djangoapp) vagrant@docker ~/golang/hello cd hello
Golang App을 위한 디렉토리를 만든다.
✔️ Golang 패키지 설치
(djangoapp) vagrant@docker ~/golang/hello apt search golang
(djangoapp) vagrant@docker ~/golang/hello sudo apt install golang
✔️ go run
go run은 현재 작성한 go 파일을 테스트하는 용도로 쓰인다.hello.go
package main
import "fmt"
func main() {
fmt.Println("hello go world")
}
vagrant@docker ~/golang/hello go run hello.go
hello go world
go 실행 파일을 실행한다.
✔️ go build
go build는 go 파일을 실행명령 파일로 만들어주는 명령어이다.
실행명령 파일은 .exe 확장자로 끝난다.
build 명령어는 run을 실행한 후 테스트를 마친 go 코드를 실행명령 파일로 빌드해주는 역할을 한다.
vagrant@docker ~/golang/hello go build -o hello hello.go
vagrant@docker ~/golang/hello ls
hello hello.go
vagrant@docker ~/golang/hello file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=b8JidWOyKMPHOlYiHlZp/En6kQIRByc4XX3VLJsRh/CToig6r9T-tXro6I2j3g/5cUWIyuef7F7582S-bk_, not stripped
vagrant@docker ~/golang/hello ./hello
hello go world
go의 특성 중 하나는 statically linked 방식을 사용한다는 것이다.
✔️ Golang 컴파일 방식
Go는 컴파일 하는데 Graphical Application은 따로 필요하지 않고 파일의 이름에 대해서도 영향을 받지 않는다.
단지, 단 하나의 main() function만 존재하면 되고 시작점이기 때문에 오직 하나만 main()이 가능하다.
이를 statically linked executable file (.exe) 파일로 만들려면 build
명령어를 활용한다.
(djangoapp) vagrant@docker ~/golang/hello ls -l
total 1976
-rw-rw-r-- 1 vagrant vagrant 141 May 12 16:04 Dockerfile
-rw-rw-r-- 1 vagrant vagrant 22 May 12 11:29 go.mod
-rwxrwxr-x 1 vagrant vagrant 2008801 May 12 11:29 hello
-rw-rw-r-- 1 vagrant vagrant 75 May 12 10:48 hello.go
파일의 크기가 매우 큰 것을 볼 수 있다. 이는 statically linked 됐기 때문이고
이것이 의미하는 바는 이 파일을 실행하는데 있어 어떠한 외부 라이브러리도 필요없다는 뜻이다.
✔️ Golang App을 Docker Image로 빌드하기
✔️ Dockerfile 작성하기
vagrant@docker ~/golang/hello vi Dockerfile
vagrant@docker ~/golang/hello cat Dockerfile
FROM golang:1.18-buster
COPY hello.go /app/hello.go
WORKDIR /app
RUN go build -o hello hello.go
vagrant@docker ~/golang/hello vi Dockerfile
vagrant@docker ~/golang/hello docker build -t gohello .
Sending build context to Docker daemon 2.013MB
Step 1/7 : FROM golang:1.18-buster AS gobuilder
---> addc000ec7ea
Step 2/7 : COPY hello.go /app/hello.go
---> Using cache
---> fd39d9371846
Step 3/7 : WORKDIR /app
---> Using cache
---> 44ed00c0f7e1
Step 4/7 : RUN go build -o hello hello.go
---> Using cache
---> 41ad08d97770
Step 5/7 : FROM scratch
--->
Step 6/7 : COPY --from=gobuilder /app/hello /
---> 3fecd32e4e5f
Step 7/7 : CMD ["/hello"]
---> Running in bfec5f60208e
Removing intermediate container bfec5f60208e
---> b041d0066e82
Successfully built b041d0066e82
Successfully tagged gohello:latest
vagrant@docker ~/golang/hello docker images | grep gohello
gohello latest b041d0066e82 7 seconds ago 1.76MB
vagrant@docker ~/golang/hello docker run gohello
hello go world
vagrant@docker ~/golang/hello docker images | grep gohello
gohello latest b041d0066e82 7 seconds ago 1.76MB
✔️ go.mod 오류
Tutorial: Get started with Go - The Go Programming Language
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
해당 오류 발생 이유 ?
go.mod 파일이 없기 때문이다.
✔️ Go module이란 ?
Go 모듈은 go 패키지들의 종속성을 관리하는 패키지 관리 시스템이다.
Go의 모듈 개념은 Go 애플리케이션 내의 종속성 문제를 처리하기 위해 도입되었다.
모듈은 패키지를 트리 형식으로 저장하고 있으며, 루트 트리에는 go.mod 파일이 있다.
저장소, 모듈 및 패키지 간의 관계는 아래와 같다.
repository
|-- module1
| -- package1
| -- src1.go
| -- src2.go
| -- go.mod
| -- package2
| -- src.go
|-- module2
| -- package
| --src.go
| -- go.mod
저장소에는 하나 이상의 Go 모듈이 포함된다.
각 모듈에는 하나 이상의 Go 패키지가 포함되어 있다.
각 패키지는 단일 디렉토리에 있는 하나 이상의 Go 소스 파일로 구성된다.
✔️ go.mod란 ?
go.mod
는 모듈을 정의하고 종속성 정보를 저장하고 있는 파일이다.
이 파일을 통해 패키지들을 관리하게된다.
module은 루트 디렉터리에 하나의 go.mod 파일을 갖고 있다.
✔️ go.mod 생성하기
vagrant@docker ~/golang/hello go mod init hello # 이름은 알아서 지정
go: creating new go.mod: module hello
vagrant@docker ~/golang/hello ls
Dockerfile go.mod hello hello.go # go.mod 라는 파일이 만들어진다.
vagrant@docker ~/golang/hello cat go.mod
module hello
go 1.13
vagrant@docker ~/golang/hello go run .
hello go world
vagrant@docker ~/golang/hello go build .
vagrant@docker ~/golang/hello ls
Dockerfile go.mod hello hello.go
go.mod 파일이 있다면 파일의 이름을 직접 지정하지 않아도 run
, build
명령 실행 가능
✔️ Dockerfile 작성하기 (멀티 스테이지 빌드)
vagrant@docker ~/golang/hello vi Dockerfile
vagrant@docker ~/golang/hello cat Dockerfile
FROM golang:1.18-buster AS gobuilder
COPY . /app
WORKDIR /app
RUN go build .
FROM scratch
COPY --from=gobuilder /app/hello /
CMD ["/hello"]
✔️ Golang App 이미지 빌드
vagrant@docker ~/golang/hello docker build -t gohello .
Sending build context to Docker daemon 2.014MB
Step 1/7 : FROM golang:1.18-buster AS gobuilder
---> addc000ec7ea
Step 2/7 : COPY . /app
---> d958c10c42d1
Step 3/7 : WORKDIR /app
---> Running in 0568fa621248
Removing intermediate container 0568fa621248
---> 737d940b5687
Step 4/7 : RUN go build .
---> Running in 0f225ce83ecb
Removing intermediate container 0f225ce83ecb
---> bd05a2b5f12a
Step 5/7 : FROM scratch
--->
Step 6/7 : COPY --from=gobuilder /app/hello /
---> 209c63a5a210
Step 7/7 : CMD ["/hello"]
---> Running in dd0033ac186e
Removing intermediate container dd0033ac186e
---> 63ece863ecd0
Successfully built 63ece863ecd0
Successfully tagged gohello:latest
✔️ 외부 패키지를 쓰는 예제
Flask나 Django 모두 외부 라이브러리를 사용했다.
파이썬 인터프리터 자체에 포함된 라이브러리가 아닌 외부 라이브러리를 pip 명령으로 설치했다.
지금까지의 예제는 Go의 표준 패키지만 사용하였고 외부 라이브러리(패키지)를 사용하지 않았다.
✔️ gin 외부 패키지
gin
이라고 하는 외부 패키지를 사용해보자
Golang에서 제일 많이 쓰이는 웹 프레임워크이다.
https://github.com/gin-gonic/gin
vagrant@docker ~/golang mkdir gogin
vagrant@docker ~/golang cd gogin
vagrant@docker ~/golang/gogin go mod init gogin
go: creating new go.mod: module gogin
vagrant@docker ~/golang/gogin vi gogin.go
vagrant@docker ~/golang/gogin cat gogin.go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
import해서 외부 패키지를 가져온다.
참고로 python, node.js, Ruby는 별도로 패키지 서버가 존재하여 패키지 서버에서 패키지를 가져온다.
python은 pip, node.js는 npm, Ruby는 jam이라는 명령을 이용해 외부 패키지를 가져온다.
따라서 패키지 서버에 장애가 나면 패키지를 받아올 수 없다.
패키지 서버가 있다는 것은 중앙 집중화된 서버가 있다는 것이다. (물론 단일 서버는 아니다.)
이와 다르게 Go는 공식적인 패키지 서버를 두지 않는다.
github, gitlab, s3 등 인터넷에서 가져오게 된다.
✔️ gin 패키지의 설치
vagrant@docker ~ ls
a.sh busybox-1.35.0 centos7.tar contents go httpd image-build x
a.txt busybox-1.35.0.tar.bz2 clang focal-v2 golang httpd.conf node
b.txt centos7 compose focal-v2.tar hello-world.tar httpd.tar python
vagrant@docker ~ cd go
vagrant@docker ~/go ls
pkg
vagrant@docker ~/go cd pkg
vagrant@docker ~/go/pkg ls
mod sumdb
홈 디렉토리에 go 라는 디렉토리가 만들어져있고 그 하위에 pkg 라는 디렉토리가 있다.
gin 패키지를 설치할 때 홈 디렉토리의 go 하위의 pkg 디렉토리에 설치된다.
✔️ gin mod tidy
vagrant@docker ~/golang/gogin go mod tidy
vagrant@docker ~/golang/gogin ls
go.mod go.sum gogin.go
파이썬에서는 pip3 freeze 명령을 이용해 설치된 패키지 목록을 파일로 만들었다.
go는 go mod tidy
라는 명령을 이용한다. go.sum 이라는 파일이 만들어진다.
결과적으로는 파이썬의 requirements.txt와 동일한 목적을 가진다.
✔️ Dockerfile 작성하기
vagrant@docker ~/golang/gogin cp ../goweb/Dockerfile .
vagrant@docker ~/golang/gogin vi Dockerfile
vagrant@docker ~/golang/gogin cat Dockerfile
FROM golang:1.18-buster AS gobuilder
ENV CGO_ENABLED 0
COPY . /app
WORKDIR /app
RUN go build -o gogin .
FROM scratch
COPY --from=gobuilder /app/gogin /
CMD ["/gogin"]
EXPOSE 8080
여기서 중요한 점은 CGO_ENABLED 설정이다.
go lib 내부에서 c의 구조체를 참조하는 경우가 있는데, 스크래치 이미지에는 아무것도 없기 때문에
c의 구조체를 참조하지 않도록 환경변수로 c와 관련된 기능을 꺼줘야 한다.
✔️ Gogin App 이미지 빌드하기
vagrant@docker ~/golang/gogin docker build --no-cache -t gogin .
Sending build context to Docker daemon 9.728kB
Step 1/9 : FROM golang:1.18-buster AS gobuilder
---> addc000ec7ea
Step 2/9 : ENV CGO_ENABLED 0
---> Running in 57e2193d0040
Removing intermediate container 57e2193d0040
---> 5fce18e9f8c4
Step 3/9 : COPY . /app
---> 750a396b8c0c
Step 4/9 : WORKDIR /app
---> Running in 6c69349609cc
Removing intermediate container 6c69349609cc
---> b4efdc581b90
Step 5/9 : RUN go build -o gogin .
---> Running in fd8fcd983b65
go: downloading github.com/gin-gonic/gin v1.7.7
go: downloading github.com/gin-contrib/sse v0.1.0
go: downloading github.com/mattn/go-isatty v0.0.12
go: downloading github.com/go-playground/validator/v10 v10.4.1
go: downloading github.com/golang/protobuf v1.3.3
go: downloading github.com/ugorji/go/codec v1.1.7
go: downloading gopkg.in/yaml.v2 v2.2.8
go: downloading golang.org/x/sys v0.0.0-20200116001909-b77594299b42
go: downloading github.com/ugorji/go v1.1.7
go: downloading github.com/go-playground/universal-translator v0.17.0
go: downloading github.com/leodido/go-urn v1.2.0
go: downloading golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
go: downloading github.com/go-playground/locales v0.13.0
Removing intermediate container fd8fcd983b65
---> ec2b925e9a3f
Step 6/9 : FROM scratch
--->
Step 7/9 : COPY --from=gobuilder /app/gogin /
---> 8395311799d8
Step 8/9 : CMD ["/gogin"]
---> Running in 0902959cf39d
Removing intermediate container 0902959cf39d
---> 4c42404cde73
Step 9/9 : EXPOSE 8080
---> Running in d78c68fbdfd6
Removing intermediate container d78c68fbdfd6
---> 7ca0f3c3fd68
Successfully built 7ca0f3c3fd68
Successfully tagged gogin:latest
go build . 실행시 외부 패키지를 받아온다. go.sum 파일에서 패키지들을 찾아 설치한다.
vagrant@docker ~/golang/gogin docker run -d -p 80:8080 gogin
9121e38f572b0d97bbf188ea32406ce9a9bfac31ddec54eca89d23a6d692c453
'DevOps > Docker' 카테고리의 다른 글
[Docker] node.js App을 Docker Image로 빌드하기 (0) | 2022.05.12 |
---|---|
[Docker] Web App을 Docker Image로 빌드하기 (0) | 2022.05.12 |
[Docker] Django App을 Docker 이미지로 빌드하기 (0) | 2022.05.12 |
[Docker] Flask App을 Docker 이미지로 빌드하기 (0) | 2022.05.12 |
[Docker] multistage-build (멀티 스테이지 빌드) (0) | 2022.05.12 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!