Closed12

Docker で Flutter 開発環境を作ってみる

ピン留めされたアイテム
nagakutanagakuta

なんで?

このスクラップDocker にある程度慣れた。
Flutter での開発環境を構築するときに、なるべく PC を汚さないように。

環境

  • Macbook Air (M1, 2020)
    • チップ: Apple M1
  • Docker for Mac: 3.3.1
nagakutanagakuta

Container を作る

まずはコレから。

.devcontainer/flutter/Dockerfile
# Base image
FROM google/dart:2.12.4

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

# Install Flutter using fvm
RUN dart pub global activate fvm

今回は Flutter のバージョン管理に fvm を利用することにした。

.devcontainer/docker-compose.yml
version: '3.8'
services:
  <project_name>:
    build:
      context: .
      dockerfile: flutter/Dockerfile
    volumes:
      # VSCode settings
      - ../.vscode:/workspace/.vscode:cached
    command: /bin/sh -c "while sleep 1000; do :; done"
    env_file:
      - flutter/.flutter.env

…が、この段階で docker compose build --no-cache でビルドしてみると「qemu: uncaught target signal 6 (Aborted) - core dumped」と言われてしまう。
どうやら、fvm を activate する時に実行される依存関係の解決時に何かが起きているらしい。

試しに google/dart の Container 内に入って直接 fvm を activate すると、一回目は必ず失敗するが、もう一度 activate を実行すると問題なく完了した。困る。

そして、なんと fvm installFlutter のインスコもできなかった。困る。

もしかしたら、google/dart の Base Image が gcr.io/google-appengine/debian10 だからかもしれない。確かそれって Distroless で、本当に必要最低限のものしか入ってない(と思う、多分)。

nagakutanagakuta

もしかしたら、google/dart の Base Image が gcr.io/google-appengine/debian10 だからかもしれない。確かそれって Distroless で、本当に必要最低限のものしか入ってない(と思う、多分)。

と思ったが、色々試した結果 apt-get で落としてくる Dartaarch64(arm64) に対応しておらず、それ故に MacOS が arm64 から gcr.io/google-appengine/devian10 を動かすために利用している仮想化技術である qemu が「対応してないよ!」と怒っているんだろう、という結論に至った。

nagakutanagakuta

Dockerfile を見直す

google/dart をベースにするとうまく動かせないので、Ubuntu を Base Image にしてイチから構築してみる。

google/dart の Dockerfile を参考に

まず試すのは、google/dartDockerfile を参考にしながら Base Image を ubuntu に変更。
必要なコマンドラインツールも先んじてインスコしておく。

.devcontainer/flutter/Dockerfile
# Base image
-FROM google/dart:2.12.4
+FROM ubuntu:20.04

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

+# Install Dart
+RUN apt-get update && \
+    apt-get install --no-install-recommends -y gnupg2 curl git ca-certificates apt-transport-https openssh-client && \
+    curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_testing.list > /etc/apt/sources.list.d/dart_testing.list && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_unstable.list > /etc/apt/sources.list.d/dart_unstable.list && \
+    apt-get update && \
+    apt-get install dart && \

+# Clean up
+RUN apt-get clean -y && \
+    apt-get autoremove -y && \
+    rm -rf /var/lib/apt/lists/*

+# Set paths
+ENV DART_SDK /usr/lib/dart
+ENV PATH $DART_SDK/bin:/root/.pub-cache/bin:$PATH

…が、E: Unable to locate package dart と怒られる。ので、ここ の Linux でのインスコ方法を見ながら書き換えてみる。…が、同様のエラーを吐く。詰まる。

nagakutanagakuta

諦めて apt-get → zip で落としてこよう

qemu が原因で apt-get から直接 Dart をインストールできない(できていても fvm 周りが動かない)ので、諦めて zip ファイルを落として動かすことにした。

Dart を導入

.devcontainer/flutter/Dockerfile
# Base image
FROM ubuntu:20.04

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

# Install Dart
RUN apt-get update && \
-   apt-get install -y ca-certificates curl git unzip --no-install-recommends && \
+   apt-get install --no-install-recommends -y bash ca-certificates curl file git libglu1-mesa unzip xz-utils zip && \
-   curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
-   curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \
-   curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_testing.list > /etc/apt/sources.list.d/dart_testing.list && \
-   curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_unstable.list > /etc/apt/sources.list.d/dart_unstable.list && \
-   apt-get update && \
-   apt-get install dart && \
+   curl https://storage.googleapis.com/dart-archive/channels/stable/release/$DART_VERSION/sdk/dartsdk-linux-arm64-release.zip -o /tmp/dart-sdk.zip && \
+   unzip /tmp/dart-sdk.zip -d /usr/lib && rm /tmp/dart-sdk.zip

# Clean up
RUN apt-get clean -y && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/*


# Set paths
ENV DART_SDK /usr/lib/dart-sdk
ENV PATH $DART_SDK/bin:/root/.pub-cache/bin:$PATH

Dart の導入まではこれで OK 。

fvm のインストール

まずは手動で Container 内に fvm をインスコしてみる。

$ dart pub global activate fvm
...
$ which fvm
/root/.pub-cache/bin/fvm
$ fvm --version
2.0.3

よしよし。

fvm を利用しての Flutter インスコ

そして fvm installFlutter をインストールする。

$ fvm install 2.0.6
...
Building flutter tool...
/lib64/ld-linux-x86-64.so.2: No such file or directory

と怒られてしまった。ld-linux-x86-64 ということは、arm64 では動かないのだろうか。ググる。

…が、特に有力な情報は見つからず。x86_64(amd64) で起動すると qemu 起因のエラーを吐き、aarch64(arm64) で起動すると /lib64/ld-linux-x86-64.so.2: No such file or directory と怒られてしまう。詰んだ。

ちなみに、上記エラーがどこで吐かれているかというと、flutter_sdk 内の Dart で flutter tool なるものを build しているときらしい。flutter_sdk/bin/cache 内の dart_sdk を削除するたびに Flutter 側が Dart をそのフォルダ内に clone しているから、何となーくそこなんだろうな、と。まだ何が起きているかのコードをきちんと読んだわけではないので憶測もあるけど。

nagakutanagakuta

続報

Apple Silicon(M1)ではなく Intel な CPU なら問題なく環境構築できたので、その過程を以下にまとめていく予定。

環境

  • MacBook Air (13インチ, Early 2015)
    • プロセッサ: 2.2 GHz デュアルコアIntel Core i7
  • Docker for Mac: 3.3.3
nagakutanagakuta

Container を作る

前回試した Dockerfile を元に、x86_64(amd64) で動作するようにしてみる。

.devcontainer/flutter/Dockerfile
# Base image
FROM ubuntu:20.04

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

# Install Dart
ARG DART_VERSION=2.13.0
RUN mkdir -p /usr/share/man/man1 && \
    apt-get update && apt-get install -y --no-install-recommends tzdata && \
    apt-get update && \
    apt-get install -y --no-install-recommends bash ca-certificates clang cmake curl file git libglu1-mesa libgtk-3-dev ninja-build pkg-config unzip xz-utils zip && \
    curl https://storage.googleapis.com/dart-archive/channels/stable/release/$DART_VERSION/sdk/dartsdk-linux-x64-release.zip -o /tmp/dart-sdk.zip && \
    unzip /tmp/dart-sdk.zip -d /usr/lib && rm /tmp/dart-sdk.zip

# Install Flutter
ARG PATH=/usr/lib/dart-sdk/bin:$PATH
ARG PATH=/root/.pub-cache/bin:$PATH
ARG FLUTTER_VERSION=2.2.0
RUN dart pub global activate fvm --verbose && \
    fvm doctor --verbose && \
    fvm install $FLUTTER_VERSION --verbose && \
    fvm use --force $FLUTTER_VERSION --verbose && \
    fvm flutter config --enable-web --enable-linux-desktop --enable-macos-desktop --enable-windows-desktop --enable-android --enable-ios --enable-fuchsia && \
    # fvm flutter precache --verbose && \
    fvm flutter doctor --verbose

# Clean up
RUN apt-get clean -y && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/*

# Set paths
ENV FVM_ROOT=/root/.pub-cache
ENV PATH $FVM_ROOT/bin:$PATH

これで docker compose build --no-cache してみる。成功した、よしよし。

nagakutanagakuta

Container 内で Flutter プロジェクトを作成する

Container 内にて fvm を利用して Flutter をインストールできているので、Container に入って Flutter プロジェクトを生成してみる。

$ fvm flutter create foo

問題なく生成できた、よしよし。

生成されたプロジェクトを元に、マウントするファイルを docker-compose.yml で指定する。

.devcontainer/docker-compose.yml
version: '3.8'
services:
  <project_name>:
    build:
      context: .
      dockerfile: flutter/Dockerfile
    volumes:
      # Flutter files
      - ../.dart_tool:/workspace/.dart_tool:cached
      - ../.fvm:/workspace/.fvm:cached
      - ../android:/workspace/android:cached
      - ../ios:/workspace/ios:cached
      - ../lib:/workspace/lib:cached
      - ../linux:/workspace/linux:cached
      - ../macos:/workspace/macos:cached
      - ../test:/workspace/test:cached
      - ../web:/workspace/web:cached
      - ../windows:/workspace/windows:cached
      - ../.metadata:/workspace/.metadata:cached
      - ../.packages:/workspace/.packages:cached
      - ../analysis_options.yaml:/workspace/analysis_options.yaml:cached
      - ../<project_name>.iml:/workspace/<project_name>.iml:cached
      - ../pubspec.lock:/workspace/pubspec.lock:cached
      - ../pubspec.yaml:/workspace/pubspec.yaml:cached
      - ../README.md:/workspace/README.md:cached
      # VSCode settings
      - ../.vscode:/workspace/.vscode:cached
    command: /bin/sh -c "while sleep 1000; do :; done"
    env_file:
      - flutter/.flutter.env

これで必要なファイルのみが Container にマウントされるようになった、よしよし。

nagakutanagakuta

VSCodeDartFlutter のための設定

最後に ここ を参考にしながら、 VSCodeDartFlutter のための設定をする。

.vscode/settings.json
{
    "dart.flutterSdkPath": ".fvm/flutter_sdk",
    "debug.openDebug": "openOnDebugBreak",
    "[dart]": {
        "editor.rulers": [
            80
        ],
        "editor.selectionHighlight": false,
        "editor.suggest.snippetsPreventQuickSuggestions": false,
        "editor.suggestSelection": "first",
        "editor.tabCompletion": "onlySnippets",
        "editor.wordBasedSuggestions": false,
        "editor.wordWrap": "bounded",
        "editor.wordWrapColumn": 80
    },
    "files.exclude": {
        ".fvm/flutter_sdk": true
    },
    "files.watcherExclude": {
        "**/.fvm": true
    },
    "search.exclude": {
        "**/.fvm": true
    }
}

これで最強の Flutter 開発環境を作り上げることができた。満足。

nagakutanagakuta

追記

最近は Dart の公式 Docker image を利用して FVM 経由の Flutter インストールができるようになった。

.devcontainer/flutter/Dockerfile
# Base image
FROM dart:2.16-sdk

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

# Install Flutter
ARG PATH=/root/.pub-cache/bin:$PATH
ARG FLUTTER_VERSION=2.10.5
RUN dart pub global activate melos --verbose && \
    dart pub global activate fvm --verbose && \
    fvm doctor --verbose && \
    fvm install $FLUTTER_VERSION --verbose && \
    fvm use --force $FLUTTER_VERSION --verbose && \
    fvm flutter config --enable-web --enable-linux-desktop --enable-macos-desktop --enable-windows-desktop --enable-android --enable-ios --enable-fuchsia && \
    # fvm flutter precache --verbose && \
    fvm flutter doctor --verbose

# Set paths
ENV FVM_ROOT=/root/.pub-cache
ENV PATH $FVM_ROOT/bin:$PATH

これで Flutter のバージョンを管理しつつ Docker Container 内にインストールできるようになった。かなり簡潔になったと思う。

近々、記事の方も最新版に更新する予定。

このスクラップは2022/05/24にクローズされました