Setting GOPATH & Basic golang 개발

Refer 1: SettingGOPATH · golang/go Wiki · GitHub

Refer 2: Go 코드를 작성하는 방법 · golang-kr/golang-doc Wiki · GitHub

특별히 공유 목적을 위해 만든 글은 아니다. 그냥 예전에 했던 설정 방식이 기억 나지 않아 구글링을 하다가 리프레시해둬야 겠다는 단순한 의도로 끄적 거려 둠. 그러나 누군가에겐 조금의 도움이 되었기를 ...


Zsh

  • Add to ~/.zshrc

    export GOPATH=$HOME/go
  • source it

    source ~/.zshrc

Bash

  • Add to ~/.bash_profile

    export GOPATH=$HOME/go
  • source it

    source ~/.bash_profile
블로그 이미지

Barracuda

Bryan의 Tech-Log. 기록은 역사다. 나는 역사를 공유하고 그 안에서 배우며, 또 다른 역사를 써나간다

Tag Bash, GO, golang, macos, zsh

댓글을 달아 주세요


최근 Containter Orchestration 관련된 작업을 진행하고 있는데, 초기 테스트 수준의 클러스터 구성이나 솔루션의 기능 확인/검증시에 사용할 Web Server 기능을 하는 컨테이너를 주로 nginx 베이스 이미지를 사용 하고 있는데,  특정 용도에 맞게 html  파일을 수정해 주어야 하는 등 귀찮은 일 들이 많다. 도커 이미지 크기도 100MB 이상이어서 생각보다 크고... 그래서 생각한 것이 "내 맘대로 주무를 수 있는 컨테이너형 작은 웹서버" 를 만들고 언제든 사용할 수 있게 해 보자는 생각이 들었다.

 

 


어떻게 하면 작고 가벼운 웹서버를 만들고 필요할 때 언제든 사용할 수 있는가?


  • 베이스 이미지가 작아야 하므로 busybox 이미지를 쓴다(1 MB +)
  • 웹서버의 하위 페이지에 따라 특정 메시지나 정보를 보여 주는 기능을 간단하게 구현하고, 편하게 다른 기능을 추가하기 위해 go 또는 node.js를 활용한다
  • 웹서버는 실행 인자로 전달하는 TCP port 번호와 동적으로 바인딩되어야 한다(kubernetes 등에서 동적 할당 가능하도록)
  • 만들어진 이미지를 Docker Hub(hub.docker.com)에 저장한다



사전 준비 작업(Prerequisites)


  • hub.docker.com 가입, Account 확보
  • 작업 서버(PC, 가상머신 등)에 Docker engine 설치
  • go 언어 개발에 대한 최소한의 기본 지식



Go 개발 환경 설정(CentOS 7 기준) & 테스트 코딩(helloworld)


* go 바이너리를 다운로드 받고 로그인 계정에 맞게 설치/설정

[root@docker01 ~]# mkdir tmp && cd tmp

[root@docker01 tmp]# curl -LO https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100 77.7M  100 77.7M    0     0  2430k      0  0:00:32  0:00:32 --:--:-- 2437k


[root@docker01 tmp]# sudo tar -C /usr/local -xvzf go1.7.linux-amd64.tar.gz


[root@docker01 tmp]# mkdir -p ~/projects/{bin,pkg,src}

[root@docker01 tmp]# sudo vi /etc/profile.d/path.sh

...

export PATH=$PATH:/usr/local/go/bin

[root@docker01 tmp]# vi ~/.bash_profile

...

export GOBIN="$HOME/projects/bin"

export GOPATH="$HOME/projects/src"

[root@docker01 tmp]# source /etc/profile && source ~/.bash_profile

[root@docker01 tmp]# echo $GOPATH && echo $GOBIN

/root/projects/src

/root/projects/bin


* 모든 개발 작업의 시작, Hello World 를 만들고 확인

[root@docker01 ~]# cd $GOPATH

[root@docker01 src]# vi hello.go

package main

import "fmt"

func main() {

  fmt.Printf("Hello, world!!!\n")

}


[root@docker01 src]# go install $GOPATH/hello.go

[root@docker01 src]# $GOBIN/hello

Hello, world!!!



Tiny Web Server 코딩


[root@docker01 src]# vi tiny-goweb.go

/*
Tiny Web server for testing k8s cluster, by Bryan Lee, 2017-08-31
*/

// A tiny web server for viewing the environment kubernetes creates for your
// containers. It exposes the filesystem and environment variables via http
// server.
//
// Modified from explorer tiny web server of k8s team.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
)

const (
        // Name of the application
        Name = "Tiny Webserver"
        // Version of the application
        Version = "0.7"
	// Default port
	DefaultPort = 8888
)

func main() {

	var (
		portNum = flag.Int("port", DefaultPort, "Port number to serve at.")
	)

	flag.Parse()

	// Getting hostname of Docker node or Podname
	podname, err := os.Hostname()
	if err != nil {
		log.Fatalf("Error getting hostname: %v", err)
	}

	links := []struct {
		link, desc string
	}{
		{"/", "Default landing page"},
		{"/info", "Show version & usage"},
		{"/fs", "Complete file system as seen by this container."},
		{"/env", "Environment variables as seen by this container."},
		{"/podname", "Podname or Hostname as seen by this container."},
		{"/healthz", "Just respond 200 ok for health checks"},
		{"/quit", "Cause this container to exit."},
	}

	// Handlers
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "<b> Pod/Hostname: %s Port: %d</b><br/><br/>", podname, *portNum)
	})

	http.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "<b> Name: %s Version: %s Port: %d</b><br/><br/>", Name, Version, *portNum)
		fmt.Fprintf(w, "<b> Kubernetes environment explorer usage</b><br/><br/>")
		for _, v := range links {
			fmt.Fprintf(w, `<a href="%v">%v: %v</a><br/>`, v.link, v.link, v.desc)
		}
	})

	http.Handle("/fs", http.StripPrefix("/fs", http.FileServer(http.Dir("/"))))
	http.HandleFunc("/env", func(w http.ResponseWriter, r *http.Request) {
		for _, v := range os.Environ() {
			fmt.Fprintf(w, "%v\n", v)
		}
	})
	http.HandleFunc("/podname", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, podname)
	})
	http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
                w.WriteHeader(200)
		fmt.Fprintf(w, "ok")
	})
	http.HandleFunc("/quit", func(w http.ResponseWriter, r *http.Request) {
		os.Exit(0)
	})

	// Start and listen
	go log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", *portNum), nil))

	select {}
}



* 컴파일 & 실행(^C 입력시 종료)

[root@docker01 src]# go install $GOPATH/tiny-goweb.go

[root@docker01 src]# $GOBIN/tiny-goweb

^C


* 접속 & 테스트(새로운 터미널을 열어 curl 접속 테스트)

[root@docker01 ~]# curl http://localhost:8888/

<b> Pod/Hostname: docker01 Port: 8888</b><br/><br/>

[root@docker01 ~]# curl http://localhost:8888/quit

curl: (52) Empty reply from server

* 위의 이전에 접속했던 터미널에서 ^C 입력 또는 /quit PATH로 URL 을 보내면 tiny-goweb 웹서버는 종료됨



Docker 이미지 생성 & 업로드(Push)


* entrypoint.sh 스크립트는 busybox Docker 이미지 내에 복사되며, 컨테이너 인스턴스가 기동되면 자동으로 실행된다. 

* $PORT_ARGS 는 뒤에 가서 Kubernetes 에서 정의하는 YAML 내에서 동적으로 정의 가능한 port 번호이며, tiny-goweb 컨테이너(웹서버)에 바인딩 되는 포트 번호를 컨테이너 마다 동적을 다르게 바꾸어 쓰기 위한 환경 변수이다.

* build.sh 를 실행하면 Docker Hub 에 업로드(Push) 까지 수행되므로, docker login 부터 우선 실행해 두어야 한다

[root@docker01 kubeweb]# docker login -u drlee001

Password: 

Login Succeeded


[root@docker01 ~]# mkdir -p ~/docker-image-works/kubeweb && cd docker-image-works/kubeweb


[root@docker01 kubeweb]# vi entrypoint.sh 

#!/bin/sh
/home/tiny-goweb $PORT_ARGS

[root@docker01 kubeweb]# vi Dockerfile 

FROM busybox

MAINTAINER Bryan Lee, <username@maildomain.com> 

COPY ./tiny-goweb /home/
COPY ./entrypoint.sh /

RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

[root@docker01 kubeweb]# vi build.sh 

#!/bin/bash
GOOS=linux GOARCH=386 go build ~/projects/src/tiny-goweb.go
docker build -t kubeweb .
docker tag kubeweb drlee001/kubeweb
docker push drlee001/kubeweb

[root@docker01 kubeweb]# chmod +x build.sh

[root@docker01 kubeweb]# ./build.sh 

Sending build context to Docker daemon     5 MB

Step 1 : FROM busybox

 ---> d20ae45477cb

Step 2 : MAINTAINER Bryan Lee, <username@maildomain.com>

 ---> Using cache

 ---> 0c7859cc0623

Step 3 : COPY ./tiny-goweb /home/

 ---> Using cache

 ---> 8c9989def6df

Step 4 : COPY ./entrypoint.sh /

 ---> e5c99ca98558

Removing intermediate container 755cb7c50807

Step 5 : RUN chmod +x /entrypoint.sh

 ---> Running in 1e3a487fef07

 ---> 1901d5bce610

Removing intermediate container 1e3a487fef07

Step 6 : ENTRYPOINT /entrypoint.sh

 ---> Running in bf5e075f42a0

 ---> 3d2a98acacf1

Removing intermediate container bf5e075f42a0

Successfully built 3d2a98acacf1

The push refers to a repository [docker.io/drlee001/kubeweb]

3baba6a0b530: Pushed 

1ded66f9f97b: Pushed 

c5f7233ef647: Layer already exists 

6a749002dd6a: Layer already exists 

latest: digest: sha256:836f0b1a32dcf0f3db021f92c80fbf90a95dc23c5fdb9abd231a11255a724e63 size: 1152

[root@docker01 kubeweb]# ls -l

total 4896

-rwxr-xr-x. 1 root root     163  9월  8 15:20 build.sh

-rw-r--r--. 1 root root     166  9월  5 00:05 Dockerfile

-rw-r--r--. 1 root root      38  9월  8 15:25 entrypoint.sh

-rwxr-xr-x. 1 root root 4993580  9월  8 15:25 tiny-goweb



업로드된 Docker 이미지로 컨테이너 실행 & 확인 과정


[root@docker01 kubeweb]# docker images | grep kubeweb

drlee001/kubeweb                                         latest              3d2a98acacf1        57 minutes ago      6.123 MB

kubeweb                                                  latest              3d2a98acacf1        57 minutes ago      6.123 MB

[root@docker01 kubeweb]# docker rmi kubeweb

Untagged: kubeweb:latest

Untagged: drlee001/kubeweb@sha256:836f0b1a32dcf0f3db021f92c80fbf90a95dc23c5fdb9abd231a11255a724e63

[root@docker01 kubeweb]# docker rmi drlee001/kubeweb

Untagged: drlee001/kubeweb:latest

Deleted: sha256:3d2a98acacf129b7c2760a0a883603cf223d91b3ccd591d2428592b079e08f0f

Deleted: sha256:1901d5bce6109f73f14789d56d8a44532cc7bb47345750235b8846867700d823

Deleted: sha256:59c60b224638d13fb4fe8b0296fc93bb81f8b7370eec952410ca8276c1bd8e44

Deleted: sha256:e5c99ca98558d159e71ca4ae2fa1be79adf6c3b999b0cb59dfb6d85d40578a5b

Deleted: sha256:100b7cebaa91325a463e2205fa5b3e4cb8cf930212ac3dda86f0b110f6dffa86

Deleted: sha256:8c9989def6df01e86a85e350e57b389c616c6cdb7253322852ca51de4f6b446e

Deleted: sha256:d9dcde924c64da0a5c4c8457fdc721999542a1d1c640c79718d42d58278c3b88

Deleted: sha256:0c7859cc0623f4c9543e54fab31749438046001018e30799bc1bcb4b5fee1e1c

* 확인을 위해, 현재 생성된 Docker 이미지를 삭제한 후, 업로드 된 이미지로 컨테이너를 생성하고 확인한다


* Docker Hub 에 업로드된 이미지로 컨테이너를 실행한다(run = pull & start)

[root@docker01 kubeweb]# docker run -it -d --name kubeweb-test -p 8888:8888 drlee001/kubeweb

Unable to find image 'drlee001/kubeweb:latest' locally

Trying to pull repository docker.io/drlee001/kubeweb ... 

latest: Pulling from docker.io/drlee001/kubeweb

add3ddb21ede: Already exists 

3fec93edb3ab: Pull complete 

814172af256c: Pull complete 

c9fc1f897d75: Pull complete 

Digest: sha256:836f0b1a32dcf0f3db021f92c80fbf90a95dc23c5fdb9abd231a11255a724e63

cab68320b62a6a496d55af83bf345e2489d58681d8d5ae43269162cedcfbd81c

[root@docker01 kubeweb]# docker ps | grep kubeweb-test

cab68320b62a        drlee001/kubeweb                                                                                                                 "/entrypoint.sh"         49 seconds ago      Up 48 seconds       0.0.0.0:8888->8888/tcp   kubeweb-test


* 기동된 kubeweb-test 컨테이너(웹서버)로 curl 접속 테스트

[root@docker01 ~]# curl http://localhost:8888/

<b> Pod/Hostname: cab68320b62a Port: 8888</b><br/><br/>


[root@docker01 ~]# curl http://localhost:8888/info

<b> Name: Tiny Webserver Version: 0.7 Port: 8888</b><br/><br/><b> Kubernetes environment explorer usage</b><br/><br/><a href="/">/: Default landing page</a><br/><a href="/info">/info: Show version & usage</a><br/><a href="/fs">/fs: Complete file system as seen by this container.</a><br/><a href="/env">/env: Environment variables as seen by this container.</a><br/><a href="/podname">/podname: Podname or Hostname as seen by this container.</a><br/><a href="/healthz">/healthz: Just respond 200 ok for health checks</a><br/><a href="/quit">/quit: Cause this container to exit.</a><br/>



Kubernetes Cluster 내에서 kubeweb 컨테이너 기동 & 테스트


* Kubernetes 클러스터에서 컨테이너 정상 기동과 접속을 확인하기 위해 Deployment와 Service 를 정의하고 생성한다

[root@kubemaster kubeweb-test]# vi kubeweb-dep-svc.yaml 

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tiny-goweb-deploy-test
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: tiny-goweb
    spec:
      containers:
      - name: tiny-goweb
        image: drlee001/kubeweb
        env:
        - name: PORT_ARGS
          value: "--port=7777"
        ports:
        - containerPort: 7777
          name: web-port
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: tiny-goweb-svc-test
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: web-port
  selector:
    app: tiny-goweb
  type: NodePort


[root@kubemaster kubeweb-test]# kubectl create -f kubeweb-dep-svc.yaml 

deployment "tiny-goweb-deploy-test" created

service "tiny-goweb-svc-test" created


[root@kubemaster kubeweb-test]# kubectl get pods

NAME                                      READY     STATUS    RESTARTS   AGE

...

tiny-goweb-deploy-test-1854448180-pqnp7   1/1       Running   0          43s

tiny-goweb-deploy-test-1854448180-w32j7   1/1       Running   0          43s


[root@kubemaster ~]# kubectl get svc

[root@kubemaster kubeweb]# kubectl get svc

...

tiny-goweb-svc-test        10.130.131.215   <nodes>       80:30149/TCP



* curl 로 접속 테스트 수행

[root@kubemaster ~]# curl http://10.255.10.171:30149

<b> Pod/Hostname: tiny-goweb-deploy-test-1854448180-w32j7 Port: 7777</b><br/><br/>


[root@kubemaster ~]# curl http://10.255.10.171:30149

<b> Pod/Hostname: tiny-goweb-deploy-test-1854448180-sfxzf Port: 7777</b><br/><br/>[root@kubemaster ~]# 

[root@kubemaster ~]# curl http://10.255.10.171:30149/info

<b> Name: Tiny Webserver Version: 0.7 Port: 7777</b><br/><br/><b> Kubernetes environment explorer usage</b><br/><br/><a href="/">/: Default landing page</a><br/><a href="/info">/info: Show version & usage</a><br/><a href="/fs">/fs: Complete file system as seen by this container.</a><br/><a href="/env">/env: Environment variables as seen by this container.</a><br/><a href="/podname">/podname: Podname or Hostname as seen by this container.</a><br/><a href="/healthz">/healthz: Just respond 200 ok for health checks</a><br/><a href="/quit">/quit: Cause this container to exit.</a><br/>


* github repository: https://github.com/DragOnMe/tiny-goweb-for-k8s-test


- Barracuda -


[관련 포스팅 목록]

[Kubernetes] CentOS 7.3 으로 Kubernetes Cluster 구성(with Flannel)-1/4

[Kubernetes] CentOS 7.3 으로 Kubernetes Cluster 구성(노드 추가하기)-2/4

[Kubernetes] 1.7.3/1.7.4, kubeadm 으로 L3 네트워크 기반 Cluster 구성(with Calico CNI)-3/4

[Kubernetes] Hyper-converged GlusterFs integration with Heketi -4/4




블로그 이미지

Barracuda

Bryan의 Tech-Log. 기록은 역사다. 나는 역사를 공유하고 그 안에서 배우며, 또 다른 역사를 써나간다

댓글을 달아 주세요