Kubernetes 는 GoLang 으로 만들어진 대표적인 s/w 입니다. Kubernetes  구조와 비슷하게 GoLang 으로 프로젝트를 만들 때 사용되는 일반적인 디렉토리 구조를 설명하겠습니다.

 

제일 먼저 GOPATH 를 지정하고, bin 디렉토리를 PATH에 추가로 지정합니다.

$ GOPATH=/Users/ahnsk/Documents/go_workspace
$ PATH=/Users/ahnsk/Documents/go_workspace/bin:$PATH

 

다음은 go get 으로 govendor 를 설치합니다. govendor 는 dependency module 을 쉽게 다운받고 관리할 수 있습니다.

$ go get -u github.com/kardianos/govendor
$ govendor -version
v1.0.9

 

이제 본인이 생성할 프로젝트를 만들어 보겠습니다. github.com 에 있는 go 프로젝트를 다운로드 받습니다.

$ mkdir -p /Users/ahnsk/Documents/go_workspace/cookiemonster2
$ GOPATH=/Users/ahnsk/Documents/go_workspace/cookiemonster2
$ go get -u github.com/seungkyua/cookiemonster2

GOPATH 는 각 프로젝트마다 자신만의 용도로 사용하기 위해 각각 지정하는 것이 편리합니다.

 

cookiemonster2 라는 프로젝트는 GOPATH 아래의 src 디렉토리에 패키지 경로(github.com/seungkyua/cookiemonster2)로 다운로드 됩니다.

/Users/ahnsk/Documents/go_workspace/cookiemonster2/src/
github.com/seungkyua/cookiemonster2

 

프로젝트 디렉토리로 이동해서 보면 다음과 같습니다.

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    └── ...

 

일반적으로 entrypoint 가 되는 go 파일은 cmd 디렉토리 아래에 위치하고 나머지 go 파일들은 pkg 디렉토리에 패키지 구조로 위치합니다.

vendor 디렉토리는 dependency module 을 다운받은 곳이므로 이 디렉토리는 삭제를 하고, 처음부터 새롭게 구성해 보겠습니다.

$ rm -rf vendor

 

govendor init 으로 vendor 디렉토리를 생성합니다.  새롭게 생성된 vendor 디렉토리에 vendor.json 파일이 보이는데 이것은 향후 dependency module 을 다운 받을 때 활용됩니다.

$ govendor init

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    └── vendor.json

 

vendor 디렉토리 밑으로 디펜던시 module 을 다운로드 받습니다.

$ govendor get github.com/seungkyua/cookiemonster2

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    ├── appengine
    ├── appengine_internal
    ├── github.com
    ├── golang.org
    ├── google.golang.org
    ├── gopkg.in
    ├── k8s.io
    ├── sigs.k8s.io
    └── vendor.json

 

vendor 디렉토리에 dependency module 의 특정버전까지 다운 받을 수 있으니 관리가 편리해 집니다. 

현재 버전에서 labstack 의 echo v4 모듈에 버그가 있어 v3 로 다시 다운받기 위해 해당 디렉토리를 지우고 다시 다운 받을 수 있습니다. @v3 는 v3  이상의 최신 버전에 해당하는 git 브랜치나 태그를 다운받으라는 의미입니다.

$ rm -rf vendor/github.com/labstack/echo

$ govendor get github.com/labstack/echo@v3

 

여기서 govendor 의 버그로 echo 는 다운받았지만 하위 디렉토리인 echo/middleware 는 다운이 안되었으므로 추가로 vendor.json 을 수정하여 다운로드 받습니다.

$ vi vendor/vendor.json
{
   "checksumSHA1": "ynPXfBgVKquHSKkdFWk3oqSYf+g=",
   "path": "github.com/labstack/echo",
   "revision": "38772c686c76b501f94bd6cd5b77f5842e93b559",
   "revisionTime": "2019-01-28T14:12:53Z",
   "version": "v3.3.10",
   "versionExact": "v3.3.10"
},
{
   "checksumSHA1": "Rp/k+BJKpaeB9vyjEPFBW4LeFP8=",
   "path": "github.com/labstack/echo/middleware",
   "revision": "38772c686c76b501f94bd6cd5b77f5842e93b559",
   "revisionTime": "2019-01-28T14:12:53Z",
   "version": "v3.3.10",
   "versionExact": "v3.3.10"
}

$ govendor fetch github.com/labstack/echo/middleware

 

 

 

 

 

 

 

 

 

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

전쳬 에제 소스

https://github.com/seungkyua/hello-go


Go 프로그램에서 channel 을 사용할 때 가장 중요한 부분은 channel 을 한 번만 닫아야 한다는 것이다. 그렇지 않고 닫힌 channel 을 중복해서 닫으려고 하면 panic 이 발생한다. 그래서 Discovery Go 책에서는 channel 에 값을 보내는 쪽에서 닫는 패턴을 추천한다.


프로젝트로 완성하는 Go 프로그래밍(Go Programming Blueprints Second Edition) 의 chat 예제를 보면 client 가 종료되어도 client 가 가지고 있는 채널을 닫지 않는 에러가 있어 이를 간단히 수정했다.


client.go 의 client struct 에 필요없는 room 변수는 삭제했다. (나중에 필요하면 추가할지도)

대신 read 메소드에 root 의 forward channel 을 인자로 받는다. 

type client struct {
socket *websocket.Conn
send chan []byte
}


read 메소드에는 socket close 하는 부분이 있는데 socket 에러가 나면 read 가 에러가 날 것이고 이 때 defer 로 channel 닫는 부분을 추가한다. write 메소드에는 중복을 피하기 위해서 channel 닫는 부분을 넣지 않았다.


func (c *client) read(forward chan<- []byte) {
defer func() {
c.socket.Close()
log.Println("Client socker read closed.")
close(c.send)
log.Println("Client send channel closed.")
}()
for {
_, msg, err := c.socket.ReadMessage()
if err != nil {
log.Println("Client Socket ReadMaessage error")
return
}
forward <- msg
}
}

 

 root.go 에서는 쓰이고 있지는 않지만 client 에 leave 할 경우 기존 client channel 닫는 소스 대신 client socket 을 닫는 부분으로 변경했다. range 로 모든 client channel 에 값을 보내고 있기 때문에 여기는 보내는 channel 이지만 channel 을 닫기가 어렵다. 그래서 client 에서 channel 을 닫는 로직을 추가했다.

 

root struct 에서 생성한 forward, join, leave channel 은 처리하지 않았다. 나중에 room 에 client 가 아무도 없을 때의 로직에 추가되면 그 때 닫는 부분을 추가해야 한다.


func (r *room) run() {
go func() {
for {
select {
case client := <-r.join:
r.clients[client] = true
case client := <-r.leave:
delete(r.clients, client)
client.socket.Close()
case msg := <-r.forward:
for client := range r.clients {
client.send <- msg
}
}
}
}()
}








Posted by Kubernetes Korea co-leader seungkyua@gmail.com

1. 다운로드

https://golang.org/doc/install?download=go1.5.2.darwin-amd64.tar.gz     # Mac

https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz           # Linux


$ sudo tar -C /usr/local -xzf go1.5.2.darwin-amd64.tar.gz

$ cd /usr/local

$ sudo chown -R root go


2. 환경 변수

sudo vi /etc/profile

export GOROOT=/usr/local/go                                 # go 설치 위치

export PATH=$PATH:/usr/local/go/bin                      # go 실행파일 위치


$ cd Documents

mkdir -p go_workspace{,/bin,/pkg,/src}


vi .bash_profile 

export GOPATH=$HOME/Documents/go_workspace                     # go workspace 위치

export PATH=$HOME/Documents/go_workspace/bin:$PATH         # go 실행파일 위치



## go tool 다운로드

$ got get golang.org/x/tools/cmd/...



3. go 샘플 다운로드

go get github.com/GoesToEleven/GolangTraining


# kubernetes 소스 다운로드

$ go get k8s.io/kubernetes       # 이렇게 하면 git clone https://github.com/kubernetes/kubernetes


4. Go Workspace 디렉토리 위치

- bin

- pkg

- src - github.com - GoesToEleven - GolangTraining



5. editor WebStorm 다운로드 및 세팅

https://www.jetbrains.com/webstorm/download/

버전 : WebStorm-11.0.3-custom-jdk-bundled.dmg



6. golang plugin 설치

https://plugins.jetbrains.com/plugin/5047?pr=idea

버전 : Go-0.10.749.zip


# Project Open

/Users/ahnsk/Documents/go_workspace/src/github.com/GoesToEleven/GolangTraining


# Preferences 세팅

Go SDK : /usr/local/go

Go Libraries : go_worksapce/src



7. theme 다운로드 및 설정

http://color-themes.com/?view=index

Sublime Text 2.jar 다운로드


File >> import Settings 에서 Sublime Text 2.jar 선택


# Preferences 세팅

Editor -> Colors & Fonts : Scheme을 Sublime Text2로 설정



8. JavaScript Debug 를 위한 live edit plugin 설치

https://plugins.jetbrains.com/plugin/7007?pr=pycharm

LiveEdit.jar 다운로드


# Preferences 세팅

Build, Execution, Deployment -> Debugger -> Live Edit

체크 : Highlight current....

Update Auto in (ms):   16 


# 우측 상단 돋보기 클릭하여 Edit Configuration 조회

창에서 좌측 상단 + 클릭 후 JavaScript Debug 추가


# chrom 웹 스토어에서 확장 프로그램 설치

JetBrains IDE Support



# WebStorm 단축키

파일찾기 : Command + Shift + O

단어찾기 : Command + Shift + F

실행       : Crtl + Alt + R

디버그    : Ctrl + Alt + D

줄삭제    : Command + Backspace

줄복사    : Command + D

포맷       : Command + Alt + L



# go file 규칙 테스트

$ gofmt -s -w file.go


$ git rebase -i   혹은    git push -f   로 작업의 논리적인 유닛으로 커밋



# Docker contribute 시에 DCO (Developer Certificate of Origin) 설정

# commit 마다 설정

Docker-DCO-1.1-Signed-off-by: Seungkyu Ahn <seungkyua@gmail.com> (github: seungkyua)



# 혹은 hook 를 설정

$ cd docker

$ curl -o .git/hooks/prepare-commit-msg \

https://raw.githubusercontent.com/dotcloud/docker/master/contrib/prepare-commit-msg.hook

$ chmod -x .git/hooks/prepare-commit-msg



# github user 를 세팅

$ git config -set github.user seungkyua



# Channel

# deadlock 을 막을려면 채널로 값을 보내는 쪽에서 close 채널을 해야 한다.

# 채널을 받는 쪽에서는 defer sync.WaitGroup.Done() 을 한다.

# 혹은 새로운 go 루틴을 만들고 sync.WaitGroup.Wait() 으로 끝나길 기달려서 close 채널을 한다.




# 문서 보기

## 문법 에러 검사

$ go vet wordcount.go


## tar 패키지 사용법 보기

$ go doc tar


## 로컬 문서 서버 띄우기

$ godoc -http=:6060



# godep 설치

go get github.com/tools/godep

$ cd ~/Documents/go_workspace/src/github.com/tools/godep

$ go install


## godep 을 사용하는 프로젝트로 이동

$ cd ~/Documents/go_workspace/src/k8s.io/kubernetes/


## godep get 으로 Godeps/_workspace 에 패키지를 다운한다.

## _workspace 는 deprecated 예정

godep get 패키지명


 







Posted by Kubernetes Korea co-leader seungkyua@gmail.com