kubernetesでローカル環境にNGINX, golang, MySQL環境作ってみる
概要
k8sのチュートリアルやってみたし自分用のアプリケーション作ってみる!
こんな感じの構成にしたい。DB接続までやってみよう。
構築
クラスタ作成
k8sのチュートリアル通りminikube使ってローカル環境にクラスタ作る。
ちなみにこれ基本Mac想定
$ minikube stop $ # deleteしとかないとちょくちょく起動しないときある $ minikube delete $ # virtualbox重いのでhyperkitで行く $ minikube start --vm-driver=hyperkit
フロントエンド
とりあえずNginx起動させてWelcome to nginx!
表示させたい
Dockerファイルを作成する
Dockerfile
FROM nginx:1.15.8 LABEL maintainer="shintaro.0112@gmial.com" EXPOSE 80 COPY ./conf/nginx.conf /etc/nginx/conf.d/nginx.conf
./conf/nginx.conf
server { listen 8080; server_name nginx.ucwork.local; access_log /var/log/nginx/ucwork_access.log; error_log /var/log/nginx/ucwork_error.log; location / { root /usr/share/nginx/html; index index.html index.htm; } }
Docker Hubにレポジトリ登録
Docker Hubでアカウント登録し、ローカルでログインしとく。
$ docker login $ # 登録したusername $ # passwordを打ち込む
commitしてpush
$ docker build -t shintaro0123/nginx:1.0.0 . $ docker run -d -p 8080:8080 --name my-nginx-app shintaro0123/nginx:1.0.0 $ docker commit -m "何かしらのコメント" my-nginx-app shintaro0123/nginx:1.0.0 $ docker push shintaro0123/nginx:1.0.0
deployment, pod, service, pvc作成
nginx-deployment.yaml
はこんな感じにする
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 8080 selector: app: nginx tier: frontend type: LoadBalancer --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nx-pv-claim labels: app: nginx spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: nginx labels: app: nginx spec: selector: matchLabels: app: nginx tier: frontend strategy: type: Recreate template: metadata: labels: app: nginx tier: frontend spec: containers: - image: shintaro0123/nginx:1.0.0 name: nginx ports: - containerPort: 8080 name: nginx volumeMounts: - name: nginx-persistent-storage mountPath: /var/www/html volumes: - name: nginx-persistent-storage persistentVolumeClaim: claimName: nx-pv-claim
全部立ててみよう!
$ kubectl create -f nginx-deployment.yaml $ # 一度作成して何か修正したらcreateじゃなくてapply使うっぽい $ # kubectl apply -f nginx-deployment.yaml
Ingress作成
podにアクセスするためにはserviceを経由するが、service経由すると都度公開されるポートが変わったりで大変そうなので、IngressとIngressControllerなるものを使う。
アプリケーションレベルでロードバランシングするL7LBっつう奴らしい。
$ minikube addons list $ # ingressの有効化 $ minikube addons enable ingress
ingressの宣言ingress.yaml
を作成。hostの名前は自分の好きにして良い
ingressが効いてるの確認するために80->8080ポートにアクセスさせてる
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ucwork.local annotations: nginx.org/server-snippet: "proxy_ssl_verify off;" spec: rules: - host: nginx.ucwork.local http: paths: - backend: serviceName: nginx servicePort: 8080 - host: go.ucwork.local http: paths: - backend: serviceName: go servicePort: 8080
実際にingress作成
$ kubectl create -f ingress/ingress.yaml $ # 一度作成して何か修正したらcreateじゃなくてapply使うっぽい $ # kubectl apply -f ingress/ingress.yaml
動作確認
$ # 各種起動状態の確認 $ minikube addons list $ # dashboardの有効化 $ minikube addons enable dashboard $ # ブラウザが開いて各種状態がわかるページ出てくる $ minikube dashboard $ # コマンド叩いて確認してもいい $ kubectl get all $ $ # httpでアクセスしてWelcome to nginx!出れば素敵! $ curl http://`minikube ip`/ -H 'Host: nginx.ucwork.local' <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>
バックエンド
MySQL
Secret作成
パスワードとか公開しちゃいけないものをいい感じで使えるSecret利用
yourpassword
部分を自分の好きなパスワードにする
kubectl create secret generic mysql-pass --from-literal=password=yourpassword
Dockerファイル作成
Dockerfile
FROM mysql:8.0.15 LABEL maintainer="shintaro.0112@gmial.com" # 設定ファイルを配置 # (MySQLは設定ファイルの権限が777だと読み込まない) COPY ./conf/charset.cnf /etc/mysql/conf.d/charset.cnf RUN chmod 644 /etc/mysql/conf.d/* RUN apt-get update && \ apt-get install -y locales && \ rm -rf /var/lib/apt/lists/* && \ echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen && \ locale-gen ja_JP.UTF-8 ENV LC_ALL ja_JP.UTF-8
./conf/charset.cnf
[mysqld] explicit_defaults_for_timestamp = 1 character-set-server=utf8 sql_mode=NO_ENGINE_SUBSTITUTION [mysql] default-character-set=utf8
Docker Hubレポジトリにpush
commitしてpush
$ docker build -t shintaro0123/mysql:1.0.0 . $ docker run -d --name my-mysql-app shintaro0123/mysql:1.0.0 $ docker commit -m "何かしらのコメント" my-mysql-app shintaro0123/mysql:1.0.0
deployment, pod, service, pvc作成
mysql-deployment.yaml
はこんな感じ
apiVersion: v1 kind: Service metadata: name: go-mysql labels: app: go spec: ports: - port: 3306 selector: app: go tier: mysql clusterIP: None --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pv-claim labels: app: go spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: go-mysql labels: app: go spec: selector: matchLabels: app: go tier: mysql strategy: type: Recreate template: metadata: labels: app: go tier: mysql spec: containers: - image: shintaro0123/mysql:1.0.0 name: mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-pass key: password ports: - containerPort: 3306 name: mysql volumeMounts: - name: mysql-persistent-storage mountPath: /var/lib/mysql volumes: - name: mysql-persistent-storage persistentVolumeClaim: claimName: mysql-pv-claim
全部立ててみーる
$ kubectl create -f mysql-deployment.yaml $ # 一度作成して何か修正したらcreateじゃなくてapply使うっぽい $ # kubectl apply -f mysql-deployment.yaml
動作確認
MySQLに接続できることを確認。パスワードはSecretで設定したものを入れる
$ # podの名前を確認 $ kubectl get pods $ # 確認したpod NAME $ kubectl exec -it [pod NAME] bash root@go-mysql-7469cd46ff-5xdwh:/# mysql -u root -p Enter password: mysql> # データベースとテーブル作ってデータ入れとく mysql> create database ucwork; Query OK, 1 row affected (0.01 sec) mysql> use ucwork Database changed mysql> create table users(id int AUTO_INCREMENT NOT NULL PRIMARY KEY, name varchar(255) not null); Query OK, 0 rows affected (0.03 sec) mysql> mysql> insert into users values(1, "taro"); Query OK, 1 row affected (0.02 sec)
golang
goアプリケーションの作成
go全然書いたこと無いんでとりあえず、httpリクエスト受けて、MySQLからなんか取ってくるところを書く。とにかく動けばいいの精神レベル(これからちゃんと勉強したいな・・・)
main.go
package main import ( "database/sql" "fmt" "net/http" "os" _ "github.com/go-sql-driver/mysql" ) func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } func handler(w http.ResponseWriter, r *http.Request) { /** URLパス表示 */ w.Write([]byte("url path is " + r.URL.Path[1:] + "\n")) /** DB接続 */ var dbConnectQuery string dbConnectQuery = "root:" + os.Getenv("GO_DB_PASSWORD") + "@tcp(" + os.Getenv("GO_DB_HOST") + ":3306)/ucwork" db, err := sql.Open("mysql", dbConnectQuery) if err != nil { panic(err.Error()) } defer db.Close() // 関数がリターンする直前に呼び出される rows, err := db.Query("SELECT * FROM users") // if err != nil { panic(err.Error()) } columns, err := rows.Columns() // カラム名を取得 if err != nil { panic(err.Error()) } values := make([]sql.RawBytes, len(columns)) scanArgs := make([]interface{}, len(values)) for i := range values { scanArgs[i] = &values[i] } for rows.Next() { err = rows.Scan(scanArgs...) if err != nil { panic(err.Error()) } var value string for i, col := range values { // Here we can check if the value is nil (NULL value) if col == nil { value = "NULL" } else { value = string(col) } w.Write([]byte(columns[i] + ": " + value + "\n")) } fmt.Println("-----------------------------------") } }
goインストールしてビルドじゃ!!コンテナ用にクロスコンパイルする
$ env GOOS=linux GOARCH=amd64 go build main.go
Dockerファイル作成
コンパイルして出力されたmainファイルをコンテナに渡して起動させる
Dockerfile
FROM golang:1.11.5 LABEL maintainer="shintaro.0112@gmial.com" EXPOSE 8080 WORKDIR /go/src/app RUN go get github.com/go-sql-driver/mysql COPY main ./ CMD ["./main"]
Docker Hubレポジトリにpush
buildしてrunしてcommitしてpush
$ docker build -t shintaro0123/golang:1.0.0 . $ docker run -d --name my-golang-app shintaro0123/golang:1.0.0 $ docker commit -m "何かしらのコメント" my-golang-app shintaro0123/golang:1.0.0
deployment, pod, service, pvc作成
go-deployment.yaml
こんな感じで作った
apiVersion: v1 kind: Service metadata: name: go labels: app: go spec: ports: - port: 8080 selector: app: go tier: backend type: LoadBalancer --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: go-pv-claim labels: app: go spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi --- apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: go labels: app: go spec: selector: matchLabels: app: go tier: backend strategy: type: Recreate template: metadata: labels: app: go tier: backend spec: containers: - image: shintaro0123/golang:1.0.0 name: go env: - name: GO_DB_HOST value: go-mysql - name: GO_DB_PASSWORD valueFrom: secretKeyRef: name: mysql-pass key: password ports: - containerPort: 8080 name: go volumeMounts: - name: go-persistent-storage mountPath: /var/www/html volumes: - name: go-persistent-storage persistentVolumeClaim: claimName: go-pv-claim
動作確認
ingressで設定したホスト名でアクセスするとよろしくgo serviceにアクセスされる
URLのパスとデータベースに格納された値一覧が表示される。
$ curl http://`minikube ip`/abcd -H 'Host: go.ucwork.local' $ # ブラウザから見たい場合は minikube ipコマンドで出力されたipとhost名をhostsに指定
まとめ
あとはNGINXのコンテナにReactとTypeScriptでアプリケーション作ってgolangにAPIリクエスト投げる感じにしたいなぁ
webでアクセスしてDBから情報取ってくるだけなのに結構いろんなとこで詰まった・・
k8s自体は奥が深そうなので、都度都度学習していき学んでいこう。。
TODO
- MySQLのDDL,SQLを起動時に自動実行
- DockerHubとgithunの連携
- nghttpxによるhttp/2対応
- gRPCやりたい
- docker commit、push、デプロイの自動化。Skaffold?
- そもそもgolangの勉強