- 投稿日:2020-08-09T18:59:01+09:00
AzureやGoの情報を絡めた私なりのde:code 2020のセッション紹介
2020年8月8日(土)にオンラインで開催されたMicrosoft Open Tech Night主催の
にて「I am gaining the skills I want! 〜What inspired me to take one step for being a "Go MVP" through de:code and summer festival〜」というタイトルで発表をさせて頂きました。
現在GoでMVP アワードを受賞できるのは「Microsoft Azure」カテゴリーであり、de:code 2020のセッションについての発表ということで、
- Azureを知れるセッション
- 存じている方のセッション
- 知り合いの方のセッション
をピックアップして、内容紹介、私の感想、関連するGo情報などを交えて紹介しています。
興味のある方は一読して頂けると、私ながらのde:code 2020のセッションリストをAzureやGoの情報と共にお届けできると思います。
P.S. 今回のthe FINALではYAEGASHI Takeshi(@hogegashi)さんも登壇してくださり、Go製自作ツール「azbill」について発表して頂けました!
- 投稿日:2020-08-09T10:38:36+09:00
golangのio.Readerは使い回しできない
はじめに
こんにちわ、すえけん(@sueken5)です。この記事ではgolangのio.Readerが使い回しができないことを紹介します。
io.Reader
io.Readerはioパッケージで提供されているインターフェースです。(ドキュメント)
type Reader interface { Read(p []byte) (n int, err error) }具体的にこのインターフェースを満たしているものを例に挙げると
などが挙げられます。
いわゆるストリーム系のものがこのio.Readerインターフェースを満たしています。
使い回せない?
本題です。次の出力は何になるでしょうか?
package main import ( "fmt" "io/ioutil" "log" "strings" ) func main() { r := strings.NewReader("hello world") a, err := ioutil.ReadAll(r) if err != nil { log.Fatal(err) } fmt.Println("a is", string(a)) b, err := ioutil.ReadAll(r) if err != nil { log.Fatal(err) } fmt.Println("b is", string(b)) }予想される出力
a is hello world b is hello world実際の出力
a is hello world b is実際の出力だと
b
が空になってしまっています。なぜでしょうか?Read()では何が起こっている?
今回サンプルで
strings.Reader
を見てみますtype Reader struct { s string i int64 // current reading index prevRune int // index of previous rune; or < 0 } func (r *Reader) Read(b []byte) (n int, err error) { if r.i >= int64(len(r.s)) { return 0, io.EOF } r.prevRune = -1 n = copy(b, r.s[r.i:]) r.i += int64(n) // <= 内部でストリームのインデックスを持っている return }内部で
Read
が呼ばれるたびにストリームに対してのインデックスをカウントアップしています。なので次の場合
a, err := ioutil.ReadAll(r) if err != nil { log.Fatal(err) } fmt.Println("a is", string(a)) b, err := ioutil.ReadAll(r) //すでにストリームの最後までいってるから何も返さない if err != nil { log.Fatal(err) }2回目にReadAllしたい場合にストリームが最後まで読み切られているので何も返さなかったということになります。
使い回す方法
使い回す方法として
io.TeeReader
があります。(ドキュメント)先ほどの失敗例をTeeReaderを使って修正すると次のようになります。
package main import ( "fmt" "io/ioutil" "log" "io" "strings" "bytes" ) func main() { r := strings.NewReader("hello world") bBuf := new(bytes.Buffer) aBuf := io.TeeReader(r, bBuf) a, err := ioutil.ReadAll(aBuf) if err != nil { log.Fatal(err) } fmt.Println("a is", string(a)) b, err := ioutil.ReadAll(bBuf) if err != nil { log.Fatal(err) } fmt.Println("b is", string(b)) }出力
a is hello world b is hello world最後に
io.Readerは便利なのでもっと詳しくなりたいです。
- 投稿日:2020-08-09T02:23:48+09:00
レガシーエンジニアによるDocker入門
初めに
この記事は技術進化が5年前くらいで止まっている環境で働く私が、モダンな技術に触れる為に学習したことを記録したものです。
暇潰しに読んでいただければ幸いです
本記事では、
- Windows10 Home + WSL2の環境に、Dockerをインストール
- Golang + GitがインストールされているコンテナをDockerfileで立ち上げる
- VSCodeからコンテナに接続してHello World
の3つを行います。
Dockerとは?
DockerはOracleVM等と同様、仮想環境を提供するソフトウェアです。OracleVMのようにOS全体を仮想化せず、OSの一部とアプリケーションの実行環境をまとめたコンテナと呼ばれる仮想環境を提供します。
コンテナはDockerfileというテキストファイルを元に作成され、Dockerfileが同一であれば、どのOSでも同一の環境を作ることができます。
Dockerと呼ばれるものは正確にはDocker engineを指し、Docker engineはDockerコマンドの実行をサポートしています。
しかし、Docker engineはLinuxカーネルに依存するため、Linuxカーネルを持たないWindowsやmacOSでは、Docker-machineというツールを経由することでDockerコマンドの実行を行います。
※例:OracleVMとDockerにGoとMySQLの実行環境を作成する例
WSL2のインストール
まずはWindows10Homeのバージョンが1903以上であることを確認してみましょう。そうでない場合は更新が必要ですので、更新して下さい。
続いて、コルタナさんに「Windows機能の有効化または無効化」と入力し、表示された同名のプログラムを起動します。Windows Subsystem for Linux(Linux用Windowsサブシステム)という項目があるので、チェックを付けて下さい。
その後PowerShellで以下のコマンドを実行し、PCを再起動しましょう
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatformおかえりなさい。次はWSL用LinuxディストリビューションをMicrosoft Storeからダウンロードします。
Microsoft Storeにアクセスし、Ubuntu 20.04 LTSをインストールしましょう
最後に、以下のコマンドを実行して準備完了です。
wsl --set-version Ubuntu 20.04 LTS 2Dockerをインストール
それでは、いよいよDockerをインストールしましょう!
Dockerhubから、Docker for windowsのStateble版をダウンロードして実行するだけです。
何事もなく終了すれば、Docker desktop起動後コマンドが入力できるようになっているはずです。docker --version Docker version 19.03.8, build afacb8bDockerfileを元にコンテナを起動しよう
Dockerfileはテキストベースのファイルで、Dockerで作成するコンテナのレシピのようなものです。今回は GoとGitが使えて、ホストOSのc:/workspace/go下にコンテナで作成したプログラムを保存できる。というものを作りました。
# ベースイメージを決める。今回はDockerhubからGolangの最新版を取得する FROM golang:latest # プロジェクトのルートディレクトリを決定する。 WORKDIR /src/app/go-gin # ginをインストール RUN go get -u github.com/codegangsta/gin # gitをインストール RUN apt-get update && apt-get install -y git # ポートを3000に指定 EXPOSE 3000 # ホスト側の共有先ディレクトリを指定する。 VOLUME [ "/c:\workspace\go" ]このコンテナを以下のコマンドでビルドしましょう。
docker build -t gocontainer .このコマンドは、現在のディレクトリに存在するDockerfileを使って、gocontainerという名前のコンテナを作成するコマンドです。
作成後、実行します。
docker run -it gocontainer root:/src/app/go-gin#ルートユーザで、
WORKDIR
に指定したディレクトリにいることを確認しましょう
最後にGitがインストールされている事を確認します。
(ついでに今回使わないけどginが入っていることも)root:/src/app/go-gin# git --version git version 2.20.1 root:/src/app/go-gin# gin -hコンテナ上で開発しよう
VSCodeに拡張機能をインストールして、コンテナ上で開発してみます。
インストールするのは以下です。
- Docker(Microsoft)
- Remote - Containers(Microsoft)
それぞれインストールしたら、Docker拡張機能のマークをクリックしてコンテナの一覧を開きます。
起動中のgocontainerを右クリック→「
Attach Visual Stadio Code
」を選択します。暫く待つと、WORKDIRで指定したディレクトリを開いたVSCodeが別ウィンドウで表示されます。試しにhello.goを作成し、実行してみましょう。
hello.gopackage main import "fmt" func main() { fmt.Println("Hello Container") }root:/src/app/go-gin# go run hello.go Hello ContainerDockerfileのVOLUMESで指定したディレクトリにも同様のファイルが存在していれば、成功です。
終わりに
Dockerコンテナの一連の流れを見ていきました。もっと効率的にコンテナ実行ができるDocker composeやマルチステージ・ビルドに触れられなかったのが残念です。理解したら記事にします…