夢のかけら

Goエンジニアの技術ブログ

【Goland】外部パッケージをimportする時にエディタ上でエラーになる時の対処法

f:id:lampler:20211027151050p:plain

問題

go.modを作る。

$ go mod init 

main.goにimport "github/hoge/huga"を書く。

$ go mod tidy

という手順でパッケージをインストールした。しかしmain.goではimportのところでエディターがエラーを吐いている。 エディターがパッケージを見つけられていないようだ。しかし実際はちゃんと動く。

解決策

Golandの設定からモジュール統合を有効にする。 f:id:lampler:20211027150850p:plain

【Golang】go get とgo installの違い

f:id:lampler:20211027124032p:plain

go.mod

go getをすると中身が変わる。自分で触るファイルではない。

go get

このコマンドはgo.modを書き換えてソースコードのダウンロード、ビルド、インストールを行う。 環境変数GOMODCACHEで指定されているディレクトリにダウンロードされる。 コマンドのインストールで go getを使うのは非推奨。コマンドとはmainパッケージをビルドしたバイナリファイルのこと。

go mod tidy

main.goなどに import "github.com/hoge"と記述して、go mod tidyをすれば勝手にインストールされる。

go install

GitHub上からパッケージをインストールするときにmainパッケージが存在するものに対して使う。 mainパッケージがないリポジトリを指定するとエラーになる。 mainパッケージがないものをインストールするときは go getソースコードimportを記載して、go mod tidyをする。

まとめ

GitHubからパッケージをインストールする方法は2つ。mainパッケージを持つものにはgo installを使う。→コマンドになる。 それ以外はソースコードimportを書いて go mod tidyをする。

docker-composeでコンテナへの通信が届かない時の対処法

f:id:lampler:20211027053652p:plain

問題

docker-compose.ymlにポート番号を書いているのに、$ docker-compose run --rm container_name shでコンテナの中に入ってサーバを立てても http://localhost:3000/へアクセスできない。

ports:
  - "3000:3000"

原因

docker-compose run--service-portsというオプションを付けないと、ポートマッピングが無視されるから。

docker-compose run --rm --service-ports container_name shもしくは docker-compose run --rm -p 3000:3000 container_name shとすればOK!

WebStormで保存時にPrettierが効かない時の対処法

f:id:lampler:20211025134338p:plain

原因

nodeのバージョンがおかしいから。

自分は2つのプロジェクトを担当している。1つはnodeのバージョンが古いアプリケーション。もう1つはnode16をDockerに入れている新しいアプリケーションだ。 コーディング中にESLintを使いたいのでnode_modulesはコンテナの中だけじゃなくてホスト側にも設置している。 ESLintはnodeのバージョンが違うと実行できなくてエラーを吐くが、保存時に実行されるprettierはエラーを吐かない。

解決策

nnvmなどを使ってnodeもバージョンをその都度変える。非常にめんどくさいがこれしかないと思う。

npm installとnpm ciの違い

f:id:lampler:20211023102547p:plain

npm install

npmi ipackage.jsonを見てライブラリをインストールする。pacakge.jsonのバージョン指定には幅があるため、npm iする時期によってはpackage.json.lockを書き換えてしまう。 つまり完全に同じ開発環境を再現できない(可能性がある)。これはnpm iの大きな問題点と言える。

npm ci

一方でnpm cipacage.json.lockからライブラリをインストールする。(これがnpm iとの最大の違い)

具体的には↓の3つをやっている。

  1. node_modules ディレクトリの削除
  2. package-lock.json と package.json の整合性のチェック。違ったらエラーを吐く。
  3. package-lock.json から node_modules を再現

npm iではなくnpm ciを使うことで完全に同じバージョンのライブラリをインストールすることができる。 git clone 直後などはnpm ciの方が良さそうだ。

【Docker】Next.js + TypeScriptの環境構築

試行錯誤して0からDockerfileを書いた記録です。

f:id:lampler:20211010220842j:plain

まず適当にDockerfileを書く。

FROM node:16-alpine
WORKDIR /app

ビルドしてコンテナに入る。

$ docker build .
$ docker run --rm -it -p 3000:3000 a5e52242bb4f sh

コンテナの中でサーバーを立てる

/app # npm i create-next-app

/app # ls
node_modules       package-lock.json  package.json

/app # npx create-next-app sample_app --typescript

/app/sample_app # npm run dev

> sample_app@0.1.0 dev
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000

http://localhost:3000 へGo!とりあえず無事に動いてる。

f:id:lampler:20211010210341p:plain

マウントする

$ docker run -it --rm -p 3000:3000 -v `pwd`:/app 3ff9c4e9af64 sh

/app # npm i create-next-app

/app # npx create-next-app sample_app --typescript

/app # cd sample_app/
/app/sample_app # npm run dev

> sample_app@0.1.0 dev
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000

これでホストのファイルシステムと同期 & ホットリロードできるようになっている。 試しにホストのpages/index.tsxを変更すると即座に変更が確認できる。

Gitで管理する

ホスト側では プロジェクトのルートディレクトリにDockerfileがあり、同階層に sample_appディレクトリがある。ルートディレクトリ上の node_modulesおよびpackage.jsonは コンテナ上で npm i create-next-appを実行した時に作成されたものである。つまりもういらない。Dockerfilesample_appの中にいれてしまう。

$ mv Dockerfile sample_app/
$ cd sample_app
$ ls 
Dockerfile        next.config.js    package.json      styles
README.md         node_modules      pages             tsconfig.json
next-env.d.ts     package-lock.json public

このsample_appをGitの管理下に置く。適当にコミットしてpushする。

$ git init
$ git add .
$ git commit -m "first-commit"

Git Cloneをする

$ git clone https://github.com/big-of-big/sample_app
$ cd sample_app

このディレクトリには node_modulesがない。つまりコンテナなの中ではパッケージをインストールする必要がある。

 $ docer run -it --rm -v `pwd`:/app/sample_app -p 3000:3000 80ce3b29c8c7 sh
/app/sample_app # npm run dev

> sample_app@0.1.0 dev
> next dev
sh: next: not found

ということで npm installpackage.jsonから必要なパッケージをインストールする。

$ /app/sample_app # npm install

ようやくサーバーを立てる!

/app/sample_app # npm run dev

> sample_app@0.1.0 dev
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000

これで一応開発はできる?

一応これでチーム開発はできると思うけど、毎回長いrunコマンド打って、コンテナの中に入ってnpm installするのは流石にしんどい。 長いコマンドは docker-composeリファクタリング、後者の問題はDockerfileを変更して対応する。しかし長くなるので終わる。

Dockerの備忘録

  • コンテナの中に入るときは -v オプションでhostのファイルシステムと同期する
  • $ docker run -it --rm -v (ホストの絶対パス):(コンテナの絶対パス) -p 3000:3000 <イメージ名> shでコンテナの中に入る
  • Dockerfileは1つのプロジェクトに1つだとは限らない。いくつでも置ける。

ホストのイメージの一覧を確認する

$ docker images

アクティブなコンテナを表示

$ docker ps

全てのコンテナを表示

$ docker ps -a

ポートをつなげる

$ docker run -it --rm -p 8000:8000 <イメージ> bash

runについて

--rmでコンテナをexit後に消す。つまり一度きりのコンテナ。

$ docker runの詳細

  1. イメージを探す→なかったらdocker hubからpull
  2. イメージからコンテナを作成
  3. 中のプログラム(デフォルトのCMD)を実行
  4. exitする

つまり runをするたびに新しいコンテナが作成される

コンテナの削除

$ docker rm <コンテナ>

コンテナを停止

$ docker stop <コンテナ>

全消し

$ docker system prune

Dockerfile

  • イメージにタグ(別名)をつけるdocker build -t <名前> .

  • ベストプラクティス:レイヤーは最小限にする。

  • レイヤーを作るのは ADD, RUN, COPY

  • Dockerfileを書いている途中ではRUNを連発するほうがいい。なぜならキャッシュを使用することでビルドが早くなるから。

  • CMD: デフォルトのコマンドを定義する。Dockerfileには最後に一回だけ書く。一回しか使えない。

  • ADDとCOPYを使うことで、build contextのファイルをコンテナに持っていくことができる。99%はCOPYでよい。ADDはtarの圧縮ファイルを解凍するときに使う

  • Dockerfile内ではcdを使わない。代わりに WORKDIRを使う。cdを使うと&&で繋げないとルートディレクトリに戻ってきてしまう。

  • Dockerfileを変更すると必ず再度ビルドする必要がある。さもないと古いイメージが使われてしまう。

docker-compose

  • runのコマンドが長い or 複数のコンテナをまとめる役割で使用する。docker-compose.ymlに指定するパスは必ず相対パスを使う。

  • -ittty: true(綺麗に表示する) stdin_open: true(入力できるようにする) オプションである。

  • $ docker-compose upはビルドもできる。古いイメージを使わないためには--buildを使う。もしくは $ docker-compose build つまり↓の手順

  • 1 Dockerfileからイメージを作成

  • 2 作成したイメージからコンテナを作成
  • 3 コンテナを起動してデフォルトのコマンドを実行

Dockerによる開発

  1. ホストのファイルとコンテナのファイルを同期
  2. ホストの環境では原則何もインストールしない
  3. コンテナの中に入っていろいろインストール && サーバーを立てる
  4. docker-compose run <サービス名>でコンテナに対してコマンドを実行する
  5. ホストでファイルを編集→コンテナのサーバーで動作確認