Help us understand the problem. What is going on with this article?

DockerイメージにLinuxbrewをDockerfileでインストールする

この記事は株式会社クロノス「~2020年春~勝手にやりますアドベントカレンダー」の7日目の記事です!

はじめに

自分のパソコンでは環境が出来上がっている状態で
みんなで環境構築をやろう! 教えよう! となったとき。
みなさんならどうするでしょうか。

細かい差異も見逃さないために、自分のパソコンに入っているパッケージをアンインストールして、環境構築の実演をしてみせるでしょうか。

(自分のパソコンの環境をいじるのは面倒くさいので)細かいことは気にせず、手順書を作って見守る(適宜困ったことがあったら助ける)でしょうか。

今回は、「自分の環境を汚したくないけど、確実に環境構築をやってもらうために実演をしたい」ってときにDockerコンテナ使えないかなーと色々調べてみた結果は紹介させてもらいます。
※ あまり実践的ではないです。

知れること・知れないこと

※ 結果的にやっていることはubuntu18.04のイメージにLinuxbrewをDockerfileでインストールする方法になります。

知れること

  • ubuntuのイメージにLinuxbrewをDockerfileを使ってインストールする方法
  • 素人目線のDockerfileの書き方のポイント

知れないこと

  • windowsで環境構築を実演する際のDockerイメージの作り方

実現方法の考え方

おおよそmacではHomebrew使って、パッケージインストールして、環境構築等するだろうという偏見仮定の元、
「LinuxbrewをLinuxのDockerイメージに入れたら、見かけ上はmacでHomebrew使うのと変わらなくない? ほらコマンドもbrewで変わらないし……」
という安直な考えで、Linuxbrewの利用を考えます。

Linuxbrew

LinuxbrewとはHomebrewのLinux版(名前そのまま)です。
2019年2月から本家 Homebrew 2.0.0 にてLinuxbrewが正式にサポートされるとのことなので(homebrew-2.0.0)、使わない手はないです。

参考
LinuxbrewでUbuntu18.04のパッケージ管理
Linuxbrewのススメ

目標

作成したイメージのDockerコンテナに入って

$ brew doctor

とコマンドを叩いて、一発でYour system is ready to brew.と出てくることを目指します。

ホームディレクトリにLinuxbrewをインストールするDockerfile

こちらは道半ばバージョンです。
Linuxbrewは/home/linuxbrew/.linuxbrew下にインストールすることが推奨されています。
上記デフォルトのディレクトリにインストールすることで、ビルド済みバイナリがあるパッケージはバイナリをインストールできるようになります。
そのためインストール場所がデフォルトでないとbrew doctorでWarningが出ます。

ただ、Dockerfileで/home/linuxbrew/.linuxbrew配下にLinuxbrewをインストールするには、私が試した限り、少々特殊なことをする必要がありました。
こちらはこちらで「素直にDockerfileを書いたバージョン」として、記載しておきたいと思います。

こちらの方法だと/home/[ユーザ名]/.linuxbrew/にインストールされることになります。Warningが出るだけでLinuxbrewは普通に利用可能です。

FROM ubuntu:18.04
LABEL maintainer beeeeyan
#環境変数を設定
ENV DEBIAN_FRONTEND=noninteractive
ENV USER beeeeyan
ENV HOME /home/${USER}
ENV SHELL /bin/bash
ENV PW password

# 種々インストール
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    vim \
    sudo \
    locales \
    build-essential \
    ca-certificates \
    curl \
    file \
    git && \
    # 一般ユーザーアカウント追加
    useradd -m ${USER} && \
    # 一般ユーザーにsudo権限を付与
    gpasswd -a ${USER} sudo && \
    # 一般ユーザーのパスワードを設定
    echo "${USER}:${PW}" | chpasswd && \
    # ログインシェルを指定
    sed -i.bak -r s#${HOME}:\(.+\)#${HOME}:${SHELL}# /etc/passwd && \
    # localの設定
    locale-gen en_US.UTF-8

# コマンドを実行するUSERを変更
USER ${USER}
# 作業ディレクトリを指定
WORKDIR ${HOME}

# Linuxbrewをインストール
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)" && \
# pathの設定
    echo 'export PATH=${HOME}/.linuxbrew/bin:$PATH' >> .bash_profile

説明

素人目線のDockerfileの書き方にも触れています。
今回の「Linuxbrewのインストール」に深く関わる箇所には気持ち最初に☆付けました。

LABEL maintainer beeeeyan

MAINTAINER(作成者情報)はDocker 1.13から非推奨(deprecated)となっているそうです。LABELで書きましょう。
参考 : 1.13以降はMAINTAINERの代わりにLABELを使うようにしよう

ENV DEBIAN_FRONTEND=noninteractive

brew doctorで出てくるエラーを潰す仮定でlocalesをインストールすることにしたのですが(後述)、localesをインストールしようとするとapt-get install自体が止まったので設定しました。詳しくは以下参照ください。
参考 : Docker Ubuntu18.04でtzdataをinstallするときにtimezoneの選択をしないでinstallする

RUN apt-get update && \
    apt-get install -y --no-install-recommends \

ここいらへんは呪文ですね。--no-install-recommendsの意味を知らなかったのですが「指定したもの以外余計なものは入れない」ということみたいです。
参考 : #Linux #Ubuntu #docker #Dockerfile のこれは何? apt-get install --no-install-recommends

    vim \
    sudo \
    locales \
    build-essential \
    ca-certificates \
    curl \
    file \
    git && \
    ~省略~
   # localの設定
    locale-gen en_US.UTF-8
  • vimsudo
    あると便利かな、くらいで入れています。sudoに関しては「完成版」では必須です。

  • locales…(省略)…locale-gen en_US.UTF-8
    brew doctorとコマンド叩いて、以下のようなエラーが出たのでインストール&設定しました。

    warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory …(省略)

  • build-essentialca-certificatescurlfilegit
    調べてもらったらわかりますが、build-essentialcurlfilegitについては、Linuxbrewをインストールするときに公式で先にインストールするよう指定されているパッケージです。
    ポイントは ca-certificatesを指定するところにあります。(これがないとcurlなどを使っても通信ができません)このパッケージは普段は自動でインストールされるものです。勘のいい方はお分かりかと思いますがapt-get install--no-install-recommendsを指定した影響で明示的に書いておく必要が出てきたパッケージです。
    参考 : 公式

    # 一般ユーザーアカウント追加
    useradd -m ${USER} && \
    # 一般ユーザーにsudo権限を付与
    gpasswd -a ${USER} sudo && \
    # 一般ユーザーのパスワードを設定
    echo "${USER}:${PW}" | chpasswd && \
    # ログインシェルを指定
    sed -i.bak -r s#${HOME}:\(.+\)#${HOME}:${SHELL}# /etc/passwd && \

☆ 一般ユーザを追加している部分
ユーザを追加する理由はrootユーザでLinuxbrewをインストールしようとするエラーになるからです。参考先の情報からsedコマンドの書き方は多少調整しました。
参考 : Dockerで開発環境を仮想化する

# コマンドを実行するUSERを変更
USER ${USER}
# 作業ディレクトリを指定
WORKDIR ${HOME}

コマンドを実行するユーザとディレクトリを作成したユーザに変更しています。

後は公式のインストールコマンド叩いて.bash_profileにLinuxbrewのパス(今回だと/home/[ユーザ名]/.linuxbrew/bin)を指定するだけです。

なぜ「素直な書き方」では/home/linuxbrew/.linuxbrewにインストールできないのか?

素直な書き方だとビルド中に以下のような応答が求められます。

==> Select the Homebrew installation directory
- Enter your password to install to /home/linuxbrew/.linuxbrew (recommended)
- Press Control-D to install to /home/[ユーザ名]/.linuxbrew
- Press Control-C to cancel installation

ここでEnter your passwordできなくてつみます。
ただ不思議とControl-Dの挙動はしてくれて、/home/[ユーザ名]/.linuxbrewにインストールされるという寸法です。

[完成版]/home/linuxbrew/.linuxbrewにLinuxbrewをインストールするDockerfile

ほんの少しトリッキーなことをしたのですが、以下でうまくいきました。

FROM ubuntu:18.04
LABEL maintainer beeeeyan
#環境変数を設定
ENV DEBIAN_FRONTEND=noninteractive
ENV USER beeeeyan
ENV HOME /home/${USER}
ENV SHELL /bin/bash
ENV PW password

# 種々インストール
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    vim \
    sudo \
    locales \
    build-essential \
    ca-certificates \
    curl \
    file \
    git && \
    # 一般ユーザーアカウント追加
    useradd -m ${USER} && \
    # 一般ユーザーにsudo権限を付与
    gpasswd -a ${USER} sudo && \
    # 一般ユーザーのパスワードを設定
    echo "${USER}:${PW}" | chpasswd && \
    # ログインシェルを指定
    sed -i.bak -r s#${HOME}:\(.+\)#${HOME}:${SHELL}# /etc/passwd && \
    # localの設定
    locale-gen en_US.UTF-8 && \
    # linuxbrewの「Alternative Installation」を実行
    git clone https://github.com/Homebrew/brew /home/linuxbrew/.linuxbrew/Homebrew && \
    mkdir /home/linuxbrew/.linuxbrew/bin && \
    ln -s /home/linuxbrew/.linuxbrew/Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin && \
    eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)

# コマンドを実行するUSERを変更
USER ${USER}
# 作業ディレクトリを指定
WORKDIR ${HOME}

# Linuxbrew関連のフォルダ作成
RUN echo ${PW} | sudo -S mkdir -p /home/linuxbrew/.linuxbrew/etc \
    /home/linuxbrew/.linuxbrew/include \
    /home/linuxbrew/.linuxbrew/lib \
    /home/linuxbrew/.linuxbrew/opt \
    /home/linuxbrew/.linuxbrew/sbin \
    /home/linuxbrew/.linuxbrew/share \
    /home/linuxbrew/.linuxbrew/var/homebrew/linked \
    /home/linuxbrew/.linuxbrew/var/homebrew/locks \
    /home/linuxbrew/.linuxbrew/Cellar && \
    # 権限変更
    echo ${PW} | sudo -S chown -R ${USER} /home/linuxbrew/.linuxbrew/etc \
    /home/linuxbrew/.linuxbrew/include \
    /home/linuxbrew/.linuxbrew/lib \
    /home/linuxbrew/.linuxbrew/opt \
    /home/linuxbrew/.linuxbrew/sbin \
    /home/linuxbrew/.linuxbrew/share \
    /home/linuxbrew/.linuxbrew/var/homebrew/linked \
    /home/linuxbrew/.linuxbrew/Cellar \
    /home/linuxbrew/.linuxbrew/Homebrew \
    /home/linuxbrew/.linuxbrew/bin \
    /home/linuxbrew/.linuxbrew/var/homebrew/locks && \
    # パスの設定
    echo 'export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"' >> .bash_profile && \
    # パスの反映
    . ~/.bash_profile && \
    # brew doctorの実行
    brew doctor

ポイントは公式の「Alternative Installation」の部分です。

    # linuxbrewの「Alternative Installation」を実行
    git clone https://github.com/Homebrew/brew /home/linuxbrew/.linuxbrew/Homebrew && \
    mkdir /home/linuxbrew/.linuxbrew/bin && \
    ln -s /home/linuxbrew/.linuxbrew/Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin && \
    eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)

「Alternative Installation」で説明されている内容は、任意の場所にLinuxbrewをインストールする際によく利用されるコマンドです。これをデフォルトの場所にインストールする方式で利用します。
つまり「Alternative Installation」に書かれているインストール場所~/.linuxbrew/Homebrew/home/linuxbrew/.linuxbrew/Homebrewに変更します。(変更した状態のものが上記コマンドです)

# Linuxbrew関連のフォルダ作成
RUN echo ${PW} | sudo -S mkdir -p /home/linuxbrew/.linuxbrew/etc \
    /home/linuxbrew/.linuxbrew/include \
    /home/linuxbrew/.linuxbrew/lib \
    /home/linuxbrew/.linuxbrew/opt \
    /home/linuxbrew/.linuxbrew/sbin \
    /home/linuxbrew/.linuxbrew/share \
    /home/linuxbrew/.linuxbrew/var/homebrew/linked \
    /home/linuxbrew/.linuxbrew/var/homebrew/locks \
    /home/linuxbrew/.linuxbrew/Cellar && \
    # 権限変更
    echo ${PW} | sudo -S chown -R ${USER} /home/linuxbrew/.linuxbrew/etc \
    /home/linuxbrew/.linuxbrew/include \
    /home/linuxbrew/.linuxbrew/lib \
    /home/linuxbrew/.linuxbrew/opt \
    /home/linuxbrew/.linuxbrew/sbin \
    /home/linuxbrew/.linuxbrew/share \
    /home/linuxbrew/.linuxbrew/var/homebrew/linked \
    /home/linuxbrew/.linuxbrew/Cellar \
    /home/linuxbrew/.linuxbrew/Homebrew \
    /home/linuxbrew/.linuxbrew/bin \
    /home/linuxbrew/.linuxbrew/var/homebrew/locks && \

後半はbrew doctorと打って怒られる部分を先回りして処理しています。
sudoで求められるパスワードはecho-Sオプションで乗り越え、
前半は必要なフォルダの作成・後半はフォルダの権限の変更(rootユーザではLinuxbrewが利用できないので)、、といった具合です。
権限の変更はエラーでは${whoami}でしたが、Dockerfileの統一感を考えて${USER}でここでは書きました。

    # brew doctorの実行
    brew doctor

パスを追加して、最後に一回brew doctorを実行しておきます。
一回目のbrew doctorでは、一部brewのツールらしきものがインストールされます。(一発でYour system is ready to brewと出てこない!)

コンテナを立ち上げるまで〜〜

ビルドします。(試行錯誤する段階では、私はAutomated Build Dockerでやってました)
Dockerfileがカレントディレクトリに存在する状態で以下コマンドを実行

$ docker build -t [イメージ名の指定] .

コンテナの起動

$ docker run --name [コンテナ名の指定] -it -d [イメージ名] /bin/bash

起動中のコンテナに入る
※ちょっとした話ですが--loginをつけておかないと.bash_profileに指定した設定が反映されないのでご注意ください。(パスが反映されずbrew doctorが実行できない…)

起動中のコンテナに入る

$ docker exec -it [コンテナ名] /bin/bash --login

brew doctor
スクリーンショット 2020-03-06 0.22.19.png

今回の目標達成です!

参考

kronos-jp
AI開発・WEB開発・システム開発・Android開発・iOS開発・IT研修・トレーニング・新入社員研修などを行う企業です。
https://www.kronos.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした