Dockerで開発環境を作成するメモ4

ホスト環境を汚さずに例えば、「Node.jsとPythonが使える環境を作成したい」としたときにそれぞれのコンテナを展開して、docker execで侵入すればできないことはない。

ただこの場合だと、同時に実行できないので、それぞれのコンテナに行き来する必要がある。とりあえずあるバージョンの組み合わせで良いので、複数のイメージをマージするような形で実行環境のイメージおよび単一のコンテナが作成できないのかモヤモヤしている。

マルチステージ・ビルドでほかのイメージからイメージへコピーする

https://qiita.com/izumin5210/items/cf14a1ea58fb82d36bb2
https://tech.actindi.net/2019/06/20/084247

FROM node:12.13.1-alpine AS node-dev
FROM python:3.8.0-slim

COPY --from=node-dev /usr/local/bin/node /usr/local/bin/
:

上記を眺めると、FROMが2つあって片方のイメージから必要なものを、もう片方にCOPYすることによってマージすることによって実現している。

本来このマルチステージビルドの目的は、開発環境とデプロイ環境を1つのDockerfileで定義して、開発環境でビルドしたモジュールをデプロイ環境のイメージにコピーするような使い方らしい。

今回やりたいのは、複数言語の開発環境をサクッと構築したいことだが、FROMを2個書いたらよろしくやるほどの簡潔さではない。

ベースのイメージに入って、他の環境をapt installする。

元々ある方法だと思う。いろいろ調べたけど、やっぱりこれしかなさそうである。そのコンテナからdocker commitを使って専用のイメージを作成する

Ubuntuコンテナ+基本コマンド+ビルドツール基本セット

基本的なコマンドと日本語入力できるようにしてある

※基本セットの最新版は以下。ユーザ追加、sudoコマンドなどが追加されている。
Dockerコンテナ内でsudoできるユーザを作成する

FROM ubuntu:18.04

RUN apt-get update -qq \
  && apt-get install -y --no-install-recommends curl wget apt-transport-https \
  ca-certificates language-pack-ja \
  gcc build-essential git vim 

RUN update-locale LANG=ja_JP.UTF-8

ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

WORKDIR /home/share

CMD ["bash"]

> docker build -t ubuntu-dev:1.0 -f Dockerfile_ubuntu .

Node.jsとYarn(npmに似たパッケージマネージャ)をインストールする

上記の基本セットをベースにする

FROM ubuntu-dev:1.0

# Install Node.js and Yarn

RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - \
  && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
  
RUN apt-get install -y --no-install-recommends \
        yarn \
        nodejs \
  && rm -rf /var/lib/apt/lists/*

CMD ["bash"]

ちなみにNode.jsのセットアップするバージョンは以下のスクリプトのURLで決まる。

curl -sL https://deb.nodesource.com/setup_12.x
curl -sL https://deb.nodesource.com/setup_13.x
> docker build -t node-dev:1.0 -f Dockerfile_node .

コンテナに入って、2つの環境のパッケージが使えるようになっているか確認。

> docker run -it --rm node-dev:1.0 /bin/bash
#
# git --version
git version 2.17.1
# gcc --version
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
# node --version
v12.13.1
# yarn --version
1.21.1
# npm --version
6.12.1

Pythonとメジャーな基本モジュール

最新リポジトリのPPAを参照するようにURLを追加している。
add-apt-repositoryを使わないでPPAを追加するを参照

また、OpenCVを利用するため、libopencv-devをインストールしている。依存ライブラリなど含めて結構なサイズなので、利用しない場合はこのlibopencv-devパッケージとopencv-pythonは除去する。

FROM ubuntu18:1.1

# update PPA (ppa:deadsnakes/ppa)
# https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa

RUN apt-key adv --keyserver keyserver.ubuntu.com --recv \ f23c5a6cf475977595c89f51ba6932366a755776 \
&& echo "deb http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic main " > \
/etc/apt/sources.list.d/python.list \
&& echo "deb-src http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic main" >> \
/etc/apt/sources.list.d/python.list && apt update

# install python3.8 and pip
RUN apt install -y python3.8 libpython3.8 libpython3.8-dev python3.8-distutils \
&& ln -s /usr/bin/python3.8 /usr/bin/python \
&& ln -s /usr/bin/pydoc3.8 /usr/bin/pydoc \
&& curl -kL https://bootstrap.pypa.io/get-pip.py | python

# install major modules
RUN pip install numpy matplotlib scipy simplejson requests setuptools pandas

# install opencv for python
RUN apt install -y libopencv-dev && pip install opencv-python

CMD ["bash"]

Rust

ver1.39.0のDockerfileがgithubにupされている

https://github.com/rust-lang/docker-rust/tree/8d0f25416858e2c1f59511a15c2bd0445b402caa/1.39.0/buster

rustup-initのシェルをダウンロードして実行するだけのシンプルな構成

FROM buildpack-deps:buster

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=1.39.0

RUN set -eux; \
    dpkgArch="$(dpkg --print-architecture)"; \
    case "${dpkgArch##*-}" in \
        amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='e68f193542c68ce83c449809d2cad262cc2bbb99640eb47c58fc1dc58cc30add' ;; \
        armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='7c1c329a676e50c287d8183b88f30cd6afd0be140826a9fbbc0e3d717fab34d7' ;; \
        arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='d861cc86594776414de001b96964be645c4bfa27024052704f0976dc3aed1b18' ;; \
        i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='89f1f797dca2e5c1d75790c3c6b7be0ee473a7f4eca9663e623a41272a358da0' ;; \
        *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
    esac; \
    url="https://static.rust-lang.org/rustup/archive/1.20.2/${rustArch}/rustup-init"; \
    wget "$url"; \
    echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
    chmod +x rustup-init; \
    ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION; \
    rm rustup-init; \
    chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
    rustup --version; \
    cargo --version; \
    rustc --version;