はじめに
goa、ginと触ったので、Echoあたりも触ってみようと思ったのと、自分自身、サーバーサイドもフロントエンドも一括で担当することが多いこともあり、「どうせだ、docker環境でフロントエンドも含めて環境を作ってみっか。」というのが始まりです。
GoコンテナはAPIを配信、Vue.jsでAPIを叩いて、値を画面にレンダリング。
みたいな想定でやっています。また、nginx噛ませてルーティングさせてます。
駄文だったらすいません。
先に言っておくと、長文です。
なお、以下のようにしています。
Go
- Go Modules
- ホットリロード
を利用してます。
Vue.js
- vue-cli3
- axios
を利用してます。
環境
- Mac OS X 10.14.6(Mojave)
- Docker version 19.03.2
- docker-compose version 1.24.1
※ ベースの環境だけ記述しておきます。GoのバージョンなどはDockerfileに記述してますので。
手順
初めのファイル構造
こっからスタートします。
nginxは後から設定するのでmyapp/etc/nginx
配下は一旦空にしています。
myapp
├── docker
│ ├── go
│ │ └── Dockerfile
│ └── vue
│ └── Dockerfile
├── docker-compose.yml
└── etc
└── nginx
└── .
各Dockerfileの中身
Go
非常にシンプルです。
Goのバージョンは1.13。
Go Modulesを利用するため、ENV GO111MODULE=on
を指定。
ホットリロード環境を作りたいのでfresh
をgo get
しています。
FROM golang:1.13.1-alpine
ENV GO111MODULE=on
RUN apk update && \
apk add emacs curl git && \
go get github.com/pilu/fresh
Vue.js
nodeのバージョンは、現時点(2019年10月)で最新の8.16
。
(何をみていたのかよくわからないですね。8.16は全然最新じゃないです。)
vue-cli3を利用するので@vue/cli
をnpm install
しています。
FROM node:8.16-alpine
RUN apk update && \
npm install -g npm && \
npm install -g @vue/cli
docker-compose.ymlの中身(初期)
nginxの設定は後で足します。
まずは、GoとVue.jsのコンテナを作るところから始めていきたいので。
version: '3'
services:
vue:
build:
context: ./docker/vue
container_name: myapp-vue
ports:
- 8080:8080
volumes:
- .:/app
working_dir: /app
tty: true
# command: sh -c "cd assets && yarn install && yarn serve"
go:
build:
context: ./docker/go
container_name: myapp-go
ports:
- 8082:8082
volumes:
- .:/go/src
working_dir: /go/src/app
tty: true
# command: fresh
ちなみに、go
、vue
共にcommandがコメントアウトしているのは、一旦コンテナで作業する必要があるので、コメントアウトしています。
go
は、Go Modulesの初期設定をしてからホットリロードを設定しないとエラーになります(なりました)。
vue
は、コンテナ内でvue create
をしたいので、コメントアウトしています。
コンテナ立ち上げ
まずはなにはともあれ、ビルドします。
$ docker-compose build
※ npm周りでWARNが出る可能性がありますが、ここは無視します。
up -d
でバックグラウンド立ち上げをします(オプション-d
無くてもいいですが、その場合は以降は別タブで作業してください)。
$ docker-compose up -d
コンテナが立ち上がっているか確認。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9897f0c5c15c nginx "nginx -g 'daemon of…" 9 seconds ago Up 7 seconds 0.0.0.0:10080->80/tcp myapp-nginx
9e8c34dacba8 kaikairanban_go "/bin/sh" 11 seconds ago Up 9 seconds 0.0.0.0:8082->8082/tcp myapp-go
7178d2a496dc kaikairanban_vue "docker-entrypoint.s…" 40 seconds ago Up 39 seconds 0.0.0.0:8080->8080/tcp myapp-vue
この時点でappディレクトリがmyappディレクトリ内にできているので、ls -la
とかで確認してみてください。
Goのコンテナを設定していく
appディレクトリに移動して、main.go
ファイルを作ります。
$ cd app && emacs main.go
※ emacsの部分は、vimでもなんでもいいです。筆者はemacsを使っているのでこうなります。
main.go
の中身は一旦こんな感じにしておきます。
package main
import (
"fmt"
)
func main () {
fmt.Println("Hello World !!")
}
Goのコンテナに入ります。
$ docker exec -it myapp-go /bin/sh
/go/src/app #
# コンテナ内で ls -la で確認してみるとこんな感じになっているはず。
/go/src/app # ls -la
total 4
drwxr-xr-x 4 root root 128 Oct 3 08:35 .
drwxr-xr-x 5 root root 160 Oct 3 08:25 ..
-rw-r--r-- 1 root root 90 Oct 3 08:35 main.go
drwxr-xr-x 2 root root 64 Oct 3 08:25 tmp
コンテナ内でGo Modulesの初期設定をします。
/go/src/app # go mod init
go: creating new go.mod: module app
/go/src/app # ls -la
total 8
drwxr-xr-x 5 root root 160 Oct 3 08:41 .
drwxr-xr-x 5 root root 160 Oct 3 08:25 ..
-rw-r--r-- 1 root root 20 Oct 3 08:41 go.mod
-rw-r--r-- 1 root root 90 Oct 3 08:35 main.go
drwxr-xr-x 2 root root 64 Oct 3 08:25 tmp
go.modができましたね。
Ctr + d
とかでコンテナの外に出て、go.mog
ファイルの中身を確認すると以下のうようになっています。
module app
go 1.13
では、Echoを導入していきます。
コンテナの外からで良いので、以下のようにmain.go
を編集します。
なんてことはない、Echoのクイックスタート(ほぼ)そのままです。
package main
import (
"net/http"
"github.com/labstack/echo"
)
func main () {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":8082"))
// e.Startの中はdocker-composeのgoコンテナで設定したportsを指定してください。
}
main.goが編集できたら、docker-compose.yml
のgoコンテナの記述部分のcommandのコメントアウトを外します。
# docker-compose.ymlの一部抜粋
go:
build:
context: ./docker/go
container_name: myapp-go
ports:
- 8082:8082
volumes:
- .:/go/src
working_dir: /go/src/app
tty: true
command: fresh # ここのコメントアウトを外す。
保存したら、docker-compose up
で更新します(一旦、一つ前のコンテナ内作業後、docker-compose down
でコンテナを停止しておいても良いです)。
以下のような状態になったら、Echo導入完了&ホットリロードもOnになりました。
$ docker-compose up
myapp-vue is up-to-date
Recreating myapp-go ... done
Recreating myapp-nginx ... done
Attaching to myapp-vue, myapp-go, myapp-nginx
myapp-go | 8:53:07 runner | InitFolders
myapp-go | 8:53:07 runner | mkdir ./tmp
myapp-go | 8:53:07 runner | mkdir ./tmp: file exists
myapp-go | 8:53:07 watcher | Watching .
myapp-go | 8:53:07 main | Waiting (loop 1)...
myapp-go | 8:53:07 main | receiving first event /
myapp-go | 8:53:07 main | sleeping for 600 milliseconds
myapp-go | 8:53:08 main | flushing events
myapp-go | 8:53:08 main | Started! (5 Goroutines)
myapp-go | 8:53:08 main | remove tmp/runner-build-errors.log: no such file or directory
myapp-go | 8:53:08 build | Building...
myapp-go | 8:53:14 runner | Running...
myapp-go | 8:53:14 main | --------------------
myapp-go | 8:53:14 main | Waiting (loop 2)...
myapp-go | 8:53:14 app |
myapp-go | ____ __
myapp-go | / __/___/ / ___
myapp-go | / _// __/ _ \/ _ \
myapp-go | /___/\__/_//_/\___/ v3.3.10-dev
myapp-go | High performance, minimalist Go web framework
myapp-go | https://echo.labstack.com
myapp-go | ____________________________________O/_______
myapp-go | O\
myapp-go | 8:53:14 app | ⇨ http server started on [::]:8082
上記の状態で、localhost:8082にアクセスすると、以下のような画面が表示されます。
見事に世界に挨拶ができましたね。
ちなみに、go.mod
はこんな感じになっています。
module app
go 1.13
require (
github.com/labstack/echo v3.3.10+incompatible
github.com/labstack/gommon v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc // indirect
)
Vueのコンテナを設定していく
コンテナが立ち上がっている状態で、vueのコンテナに入ります。
$ docker exec -it myapp-vue /bin/sh
/app #
vue-cliでvue環境を設定していきます。
/app # vue create assets
上記コマンドを打つと、質問形式で色々聞かれます。
? Your connection to the default yarn registry seems to be slow.
Use https://registry.npm.taobao.org for faster installation? (Y/n) Y ←Yesにします。
と聞かれた後、Vueの設定に入っていきます。
お好みで設定すれば良いと思いますが、今回は以下のようにします。
Enterを無心で押していくと、以下のような感じで設定が始まります。
サクセスすると、以下のような表示になるかと思います。
ここまできたら、Ctr + d
でコンテナを抜けます。
docker-compose down
で一旦コンテナを落としておきます。
そして、docker-compose.yml
のvueコンテナの部分でコメントアウトにしていた部分のコメントアウトを外します。
vue:
build:
context: ./docker/vue
container_name: myapp-vue
ports:
- 8080:8080
volumes:
- .:/app
working_dir: /app
tty: true
command: sh -c "cd assets && yarn install && yarn serve" # ここのコメントアウトを外す。
バックグラウンドでコンテナを立ち上げた後、vueコンテナのlogだけを表示させてみます。
$ docker-compose up -d
$ docker-compose logs -f vue
以下のような感じでvueコンテナが立ち上がればOKです。
上記画面が出た状態で、localhost:8080にアクセスすると、以下のような画面が表示されます。
Vue.js Appの世界に無事、迎え入れられてもらうことができました。
nginxのコンテナを作る
一旦、docker-compose down
で、コンテナを落としておきます。
そして、docker-compose.yml
に追記&nginx.conf
を作ります。
version: '3'
services:
vue:
build:
context: ./docker/vue
container_name: myapp-vue
ports:
- 8080:8080
volumes:
- .:/app
working_dir: /app
tty: true
command: sh -c "cd assets && yarn install && yarn serve"
go:
build:
context: ./docker/go
container_name: myapp-go
ports:
- 8082:8082
volumes:
- .:/go/src
working_dir: /go/src/app
tty: true
command: fresh
# こっから下を追加
nginx:
image: nginx
depends_on:
- go
container_name: myapp-nginx
ports:
- 80:80
environment:
- TZ=Asia/Tokyo
volumes:
- ./etc/nginx/nginx.conf:/etc/nginx/nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /api/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_pass http://go:8082/;
}
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_pass http://vue:8080/;
}
}
}
準備ができたら、docker-compose up -d
でコンテナを立ち上げます。
docker-compose logs -f
などで、go、Vueどちらのコンテナも立ち上がって、準備ができたのを確認できたら、http://localhost でアクセスしてみましょう。
この画面になったらOKです。
Vue側からGo側へリクエストを送り、値を得る。
axios
を使って、GoのAPIを叩き値を取ってくることを想定して、もう少しファイルを編集していきます。
axiosを使えるようにする。
axiosを使えるようにするため、package.json
(assetsディレクトリ内にあるはずです)を編集します。
dependencies
の部分にaxiosを追加します(バージョンは、2019年10月最新のものにしてます)。
併せて、console.log()
が入っているときにWaringが出ないようにするため、esLintConfg
のrules
に、
"no-console": "off"
を追加します。
{
...
"dependencies": {
"core-js": "^2.6.5",
"vue": "^2.6.10",
"axios": "^0.19.0"
},
...
...
"eslintConfig": {
...
"rules": {
"no-console": "off"
},
...
},
...
}
グローバルにaxiosを使えるように、main.jsに登録をします。
import Vue from 'vue'
import App from './App.vue'
// ここから
import axios from 'axios'
Vue.prototype.$axios = axios
// ここまでを追加
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
ファイルが編集できたら、docker-compose restart vue
で、設定を更新します。
axiosで、GoのAPIを叩く。
今回は超簡易的に、
- ブラウザで http://localhost にアクセス。
- APIが叩かれる(GET)。
- Go側からレスポンスを返す。
-
console.log()
を使って、ブラウザのコンソール画面でレスポンスの中身を確認する。
ということを行います。
では、App.vue
を編集していきます。
Vueのcreatedフックのなかで、axiosを使うように記述します。
(変更箇所のあるscriptタグのブロックだけ以下に表示させてます。)
// <template> のブロックがある
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
},
// createdの中でaxiosを使います。get()の中のURLは、nginx.confで設定してるので、 /api/ になっています。
created () {
this.$axios.get('http://localhost/api/')
.then(response => {
console.log(response)
})
}
}
</script>
// <style> のブロックがある
できたら、ブラウザの開発者ツールでコンソールタブを開いて、 http://localhost にアクセスしてみましょう。
(もしくは、リロードしてみましょう。)
画像のように、レスポンスが返ってきているのが確認できたらOKです。
あとは、返ってきた値を上手く調理するなどして、画面にレンダリングするとかしてみてみるといいんじゃないでしょうか。
(その辺は、余裕あったら続きを書こうと思います。記録としても残しておく意味で。)
以上。