20200809のGoに関する記事は3件です。

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〜」というタイトルで発表をさせて頂きました。

thumbnail

現在GoでMVP アワードを受賞できるのは「Microsoft Azure」カテゴリーであり、de:code 2020のセッションについての発表ということで、

  • Azureを知れるセッション
  • 存じている方のセッション
  • 知り合いの方のセッション

をピックアップして、内容紹介、私の感想、関連するGo情報などを交えて紹介しています。

興味のある方は一読して頂けると、私ながらのde:code 2020のセッションリストをAzureやGoの情報と共にお届けできると思います。

P.S. 今回のthe FINALではYAEGASHI Takeshi(@hogegashi)さんも登壇してくださり、Go製自作ツール「azbill」について発表して頂けました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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は便利なのでもっと詳しくなりたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

レガシーエンジニアによる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の実行環境を作成する例
Dockerイメージ.png

WSL2のインストール

まずはWindows10Homeのバージョンが1903以上であることを確認してみましょう。そうでない場合は更新が必要ですので、更新して下さい。

続いて、コルタナさんに「Windows機能の有効化または無効化」と入力し、表示された同名のプログラムを起動します。Windows Subsystem for Linux(Linux用Windowsサブシステム)という項目があるので、チェックを付けて下さい。

Linux用Windowsサブシステム.png

その後PowerShellで以下のコマンドを実行し、PCを再起動しましょう

Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform

おかえりなさい。次はWSL用LinuxディストリビューションをMicrosoft Storeからダウンロードします。

Microsoft Storeにアクセスし、Ubuntu 20.04 LTSをインストールしましょう
Ubuntu.png

最後に、以下のコマンドを実行して準備完了です。

wsl --set-version Ubuntu 20.04 LTS 2

Dockerをインストール

それでは、いよいよDockerをインストールしましょう!
Dockerhubから、Docker for windowsのStateble版をダウンロードして実行するだけです。
何事もなく終了すれば、Docker desktop起動後コマンドが入力できるようになっているはずです。

docker --version
Docker version 19.03.8, build afacb8b

Dockerfileを元にコンテナを起動しよう

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拡張機能のマークをクリックしてコンテナの一覧を開きます。
Docker拡張機能.png

起動中のgocontainerを右クリック→「Attach Visual Stadio Code」を選択します。

暫く待つと、WORKDIRで指定したディレクトリを開いたVSCodeが別ウィンドウで表示されます。試しにhello.goを作成し、実行してみましょう。

hello.go
package main
import "fmt"

func main() {
    fmt.Println("Hello Container")
}
root:/src/app/go-gin# go run hello.go
Hello Container

DockerfileのVOLUMESで指定したディレクトリにも同様のファイルが存在していれば、成功です。

終わりに

Dockerコンテナの一連の流れを見ていきました。もっと効率的にコンテナ実行ができるDocker composeやマルチステージ・ビルドに触れられなかったのが残念です。理解したら記事にします…

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む