Work Records

日々の作業記録です。ソフトウェアエンジニアリング全般から、趣味の話まで。

Scriptの実行環境を保証するためにDockerfileを使う

Scriptの実行環境

最近golangを使ってちょっとしたscriptを書く機会が何度かあったが、そこにDockerfileを置いておいてビルド環境や方法を固定する方法がいいなあと思ったので、メモ程度に。
goの場合は実行ファイルはコンパイル後のバイナリで依存がOS(linux or window or mac)くらいしかないと思うが、rubyやらperlやら実行環境にも依存するような場合にはサクッと動作環境をDockerfileに書いておくと簡単で良いなあと感じた。


Dockerfileを一緒に作る

例えば、sampleX.go というのがscript達だとして

┬ sample1.go
├ sample2.go
├ sample3.go
├ libs/
└ configs/

こんな感じで、scriptを作ったとする。
golang wayはよくわからないが結構こんな感じでバラバラとscriptを気軽に量産しまくっている。
(サブコマンドとか使ってmainは一つにしたほうがいいのかもしれないが。)

ここに、Dockerfileをおく

┬ sample1.go
├ sample2.go
├ sample3.go
├ libs/
├ configs/
└ Dockerfile

Dockerfileの中身はこんな感じで。

FROM golang:alpine AS build-env
RUN apk add --update git
ADD . /work
WORKDIR /work
RUN go get "github.com/go-sql-driver/mysql" && \
    GOOS=linux GOARCH=amd64 go build -o sample1 sample1.go && \
    GOOS=linux GOARCH=amd64 go build -o sample2 sample2.go && \
    GOOS=linux GOARCH=amd64 go build -o sample3 sample3.go

FROM alpine
COPY --from=build-env /work/sample1 /usr/local/bin/sample1
COPY --from=build-env /work/sample2 /usr/local/bin/sample2
COPY --from=build-env /work/sample3 /usr/local/bin/sample3

Multi Stage Buildを使っていますが、buildの環境を定義しているのはbuild-envの方。
もし特定のgoのバージョンにしたかったり自前で作ったdocker imageでやりたい場合にはFROMにそれを指定すればいいし、
必要なライブラリはRUNで実行して入れてしまえばok。

実際の手順としては、

  • scriptを修正&テストを行う
  • `Docker build . -f Dockerfile -t xxxx/yyyy` を実行する
  • 適当なレジストリにdocker push xxxx/yyyy
  • 実行したい環境で、`docker run -it --rm xxxx/yyyy /usr/local/bin/sample1`

と言った感じ。

なので基本的にはdockerエンジンだけ実行側に入って入れば全てはちゃんと整った環境で実行される、ということになる。
これで、共通のcronサーバーにあれやこれや死ぬほどinstallしなくてもよくなる!

ちなみにだいたい同じようなscriptだったのでまとめて一個のDockerfileにしているが、
かなり毛色が違って使うライブラリも違うようなものは別 Dockerfileにしたほうが良いと思う。



まとめ

dockerを使い始めると構成管理がすごい楽になるなあと実感する。
必要最低限の範囲に必要最低限のライブラリだけ入れて、それが毎回同じ状況ですぐに立ち上がる、素晴らしい!