构建用于 Flutter 构建环境的 Docker 容器失败,出现连接错误。

huangapple go评论76阅读模式
英文:

Building a docker container for flutter build environment fails with connectivity errors

问题

我会翻译代码部分的内容,以下是您提供的代码的翻译:

# 示例用法:
# 使用以下命令构建镜像:
# docker build --pull --rm -f 'Dockerfile' -t flutter_build:latest .
#   --pull 尝试始终拉取新镜像
#   --rm 在构建后删除中间生成的容器
#   -f 指定要构建镜像的文件
#   -t 设置一个标签为“label_of_container:with_version”

# 运行容器:
# docker run -p 8080:80 flutter_build
#   -p 将内部端口80映射到外部/公共端口8080 -> 访问 http://localhost:8080

ARG WORKDIR=/app

# 构建Flutter Web应用程序
FROM ubuntu:latest AS FLUTTER_BUILDER

ARG WORKDIR
ARG USER_NAME=flutter
ARG REPO_NAME=flutter
ARG BRANCH_NAME=stable

RUN apt update -y
RUN apt install -y bash curl file git unzip zip xz-utils libglu1-mesa

# 使用ADD命令绕过缓存此Docker层,每当新的Flutter版本发布到stable时都会触发
ADD https://api.github.com/repos/${USER_NAME}/${REPO_NAME}/git/refs/heads/${BRANCH_NAME} ${REPO_NAME}_${BRANCH_NAME}_version.json
RUN git clone https://github.com/${USER_NAME}/${REPO_NAME}.git -b ${BRANCH_NAME}
ENV PATH="$PATH:/flutter/bin"
RUN flutter precache

COPY . ${WORKDIR}

WORKDIR ${WORKDIR}

RUN flutter clean
RUN flutter pub get
RUN flutter build web

# 提供Flutter Web应用程序
FROM nginx:latest

ARG WORKDIR

EXPOSE 80

COPY --from=FLUTTER_BUILDER ${WORKDIR}/build/web /usr/share/nginx/html

请注意,这只是您提供的Dockerfile的翻译部分。如果您需要有关如何修复Docker容器中的Flutter问题的更多信息,请提供相关上下文。

英文:

I'm trying to setup an easy docker container with flutter installed in it. One of the commands I'm using in a RUN statement is flutter precache which somehow fails with the following error:


flutter precache -v

Downloading Linux arm64 Dart SDK from Flutter engine ada363ee93b17cfe31587b5102679885cb40837e...

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 139M 100 139M 0 0 10.6M 0 0:00:13 0:00:13 --:--:-- 10.8M
Building flutter tool...
[ +7 ms] Unable to locate an Android SDK.
[ +2 ms] executing: uname -m
[ +2 ms] Exit code 0 from: uname -m
[ ] aarch64
[ ] executing: [/flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[ +3 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[ ] 12cb4eb7a009f52b347b62ade7cb4854b926af72
[ ] executing: [/flutter/] git tag --points-at 12cb4eb7a009f52b347b62ade7cb4854b926af72
[ +15 ms] Exit code 0 from: git tag --points-at 12cb4eb7a009f52b347b62ade7cb4854b926af72
[ ] 3.7.6
[ +4 ms] executing: [/flutter/] git rev-parse --abbrev-ref --symbolic @{upstream}
[ +3 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{upstream}
[ ] origin/stable
[ ] executing: [/flutter/] git ls-remote --get-url origin
[ +3 ms] Exit code 0 from: git ls-remote --get-url origin
[ ] https://github.com/flutter/flutter.git
[ +10 ms] executing: [/flutter/] git rev-parse --abbrev-ref HEAD
[ +3 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[ ] stable
[ +25 ms] Downloading Material fonts...
[ +32 ms] HandshakeException: Connection terminated during handshake
[ +10 ms] Downloading Material fonts... (completed in 32ms)
[ ] Downloading Material fonts...
[ +18 ms] HandshakeException: Connection terminated during handshake
[ ] Downloading Material fonts... (completed in 18ms)
[ ] "flutter precache" took 93ms.
[ +3 ms] Failed to download https://storage.googleapis.com/flutter_infra_release/flutter/fonts/3012db47f3130e62f7cc0beabff968a33cbec8d8/fonts.zip. Ensure you
have
network connectivity and then try again.
HandshakeException: Connection terminated during handshake
[ +1 ms]
#0 throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
#1 ArtifactUpdater._downloadArchive (package:flutter_tools/src/cache.dart:1062:11)
<asynchronous suspension>
#2 CachedArtifact.update (package:flutter_tools/src/cache.dart:810:5)
<asynchronous suspension>
#3 Cache.updateAll (package:flutter_tools/src/cache.dart:677:9)
<asynchronous suspension>
#4 PrecacheCommand.runCommand (package:flutter_tools/src/commands/precache.dart:168:7)
<asynchronous suspension>
#5 FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1257:27)
<asynchronous suspension>
#6 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#7 CommandRunner.runCommand (package:args/command_runner.dart:209:13)
<asynchronous suspension>
#8 FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:283:9)
<asynchronous suspension>
#9 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#10 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5)
<asynchronous suspension>
#11 run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:64:9)
<asynchronous suspension>
#12 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#13 main (package:flutter_tools/executable.dart:91:3)
<asynchronous suspension>
[ +1 ms] ensureAnalyticsSent: 0ms
[ ] Running 0 shutdown hooks
[ ] Shutdown hooks complete
[ ] exiting with code 1
Failed to download https://storage.googleapis.com/flutter_infra_release/flutter/fonts/3012db47f3130e62f7cc0beabff968a33cbec8d8/fonts.zip. Ensure you have
network connectivity and then try again.
HandshakeException: Connection terminated during handshake

Executing flutter precache a second time in an interactive container (shell attached) works instantly. Any idea how to prevent/fix this error?

I already tried running the docker build with --network=host or adding things like update-ca-certificates inside the container but nothing works. Also ignoring the error and adding a second RUN flutter precache in the dockerfile doesn't work (ignoring by using RUN flutter precache; exit 0 as the first RUN)

How could I fix this?

PS: The Dockerfile I'm currently using to build a flutter build environment on MacBook Pro M1 looks like this:

# Example Usage: 
# Build the image with: 
# docker build --pull --rm -f 'Dockerfile' -t flutter_build:latest . 
#   --pull tries to always pull new images
#   --rm delete intermediate generated containers after build
#   -f specifies the file to build the image
#   -t sets a label_of_container:with_version
#
# Run it with:
# docker run -p 8080:80 flutter_build
#   The -p exposes the internal port 80 to the 
#   external/public port 8080 -> visit http://localhost:8080


ARG WORKDIR=/app


# build the flutter web app
FROM ubuntu:latest AS FLUTTER_BUILDER

ARG WORKDIR

ARG USER_NAME=flutter
ARG REPO_NAME=flutter
ARG BRANCH_NAME=stable

RUN apt update -y

RUN apt install -y bash curl file git unzip zip xz-utils libglu1-mesa

# using ADD here to bypass caching of this docker layer whenever a new flutter version was released to stable
ADD https://api.github.com/repos/${USER_NAME}/${REPO_NAME}/git/refs/heads/${BRANCH_NAME} ${REPO_NAME}_${BRANCH_NAME}_version.json
RUN git clone https://github.com/${USER_NAME}/${REPO_NAME}.git -b ${BRANCH_NAME}
ENV PATH="$PATH:/flutter/bin"
RUN flutter precache

COPY . ${WORKDIR}

WORKDIR ${WORKDIR}

RUN flutter clean
RUN flutter pub get
RUN flutter build web


# serve the flutter web app
FROM nginx:latest

ARG WORKDIR

EXPOSE 80

COPY --from=FLUTTER_BUILDER ${WORKDIR}/build/web /usr/share/nginx/html

答案1

得分: 2

以下是代码部分的翻译:

# 全局设置工作目录(仍然需要在每个阶段中引用!)
ARG WORKDIR=/app

# 构建 Flutter Web 应用程序
#
# 在第一个阶段中,只需准备一个 Ubuntu 容器
# 并安装 Flutter 工具以构建 Flutter 应用程序
FROM ubuntu:latest AS FLUTTER_BUILDER

# 设置工作目录
ARG WORKDIR

# 设置从中克隆 Flutter SDK 的 GitHub 存储库信息。
ARG USER_NAME=flutter
ARG REPO_NAME=flutter
ARG BRANCH_NAME=stable

# 使用所需的所有工具准备 Ubuntu 容器
RUN apt update -y
RUN apt install -y bash curl file git unzip zip xz-utils libglu1-mesa

# 有时 Google 服务器响应稍慢,导致握手失败
# 增加超时时间可以解决这个错误!
ENV HTTP_TIMEOUT=5000

# 在这里,我们使用 ADD 来在以下 Docker 阶段中使缓存无效,当给定的 Flutter GitHub 存储库的给定分支上有新的提交/版本时 - 注意:这取决于 GitHub API!
ADD https://api.github.com/repos/${USER_NAME}/${REPO_NAME}/git/refs/heads/${BRANCH_NAME} flutter_version.json
RUN git clone https://github.com/${USER_NAME}/${REPO_NAME}.git -b ${BRANCH_NAME}

# 现在设置 Flutter 路径,并构建 Flutter 工具并预缓存所有必要的工具,这很好
# 因为只要 ADD 不使这些阶段无效,我们就不必重建这个昂贵的部分
ENV PATH="$PATH:/flutter/bin"
RUN flutter precache

# 复制 Flutter 项目并切换到它
COPY . ${WORKDIR}
WORKDIR ${WORKDIR}

# 运行 flutter clean、pub get 然后构建 Web 版本
RUN flutter clean
RUN flutter pub get
RUN flutter build web

# 服务于 Flutter Web 应用程序
#
# 在第二个阶段中,只需从第一个阶段复制构建的 Web 文件
# 并将其作为静态网站使用基本的 Nginx 容器提供
FROM nginx:latest

# 设置工作目录
ARG WORKDIR

# 告诉使用哪个端口(不一定需要)
EXPOSE 80

# 将构建的 Flutter 静态网站复制到 Nginx 目录
COPY --from=FLUTTER_BUILDER ${WORKDIR}/build/web /usr/share/nginx/html
英文:

I just had to add an increased timeout to the http requests inside the docker container. Seems like sometimes the Google CDN servers needs some time to respond or the corporate network blocks them completely.

I did this by adding ENV HTTP_TIMEOUT=5000 in the Dockerfile somewhere before the RUN flutter precache.

When it's still failing I just had to use a VPN to get out of the corporate network and it worked again.

With that change the Flutter build environment inside of the docker container works perfectly as expected even for Mac M1 and M2 (M series in general I guess) and also for Linux ARM platforms. Therefore this can also be considered as a workaround for the cirrusci/flutter docker container which throws errors like:

===== CRASH =====
si_signo=Segmentation fault(11), si_code=1, si_addr=0x7
version=2.18.0 (stable) (Fri Aug 26 10:22:54 2022 +0000) on "linux_x64"
pid=173, thread=217, isolate_group=main(0x400305f000), isolate=main(0x40030d6000)
isolate_instructions=4001ece300, vm_instructions=4001ece300
pc 0x0000ffffa600472b fp 0x00000040103d51f0 Unknown symbol
...
...
...
pc 0x00000040020999af fp 0x00000040103d5c60 dart::MessageHandler::TaskCallback()+0x1df
pc 0x00000040021bc868 fp 0x00000040103d5ce0 dart::ThreadPool::WorkerLoop(dart::ThreadPool::Worker*)+0x148
pc 0x00000040021bccbd fp 0x00000040103d5d10 dart::ThreadPool::Worker::Main(unsigned long)+0x6d
pc 0x000000400212f488 fp 0x00000040103d5dd0 /sdks/flutter/bin/cache/dart-sdk/bin/dart+0x212f488
-- End of DumpStackTrace
qemu: uncaught target signal 6 (Aborted) - core dumped
Aborted

on most ARM architectures. As referenced in this stackoverflow post: https://stackoverflow.com/questions/73751274/flutter-pub-get-fails-in-docker

The finally used Dockerfile to serve a flutter web app compiled and served from docker looks like this (don't forget to add CORS headers to your backend API server when serving the API from a different server or even port - these must be included especially in the preflight responses!):

# setting workdir globally (still needs to be referenced in each stage!)
ARG WORKDIR=/app


# build the flutter web app
#
# in the first stage just prepare a ubuntu container
# and install the flutter tooling to build flutter apps
FROM ubuntu:latest AS FLUTTER_BUILDER

# setting the workdir
ARG WORKDIR

# setting the github repo information from 
# which the flutter sdk will be cloned.
ARG USER_NAME=flutter
ARG REPO_NAME=flutter
ARG BRANCH_NAME=stable

# preparing the ubuntu container with all necessary tools
RUN apt update -y
RUN apt install -y bash curl file git unzip zip xz-utils libglu1-mesa

# sometimes the Google servers respond a little slowly 
# which resulted in a failed handshake
# increasing the timeout solves this error!
ENV HTTP_TIMEOUT=5000

# here we use ADD to invalidad cache of the docker stages below when there is a new commit/version in the
# given flutter github repo on the given branch - watch out: depending on github api here!
ADD https://api.github.com/repos/${USER_NAME}/${REPO_NAME}/git/refs/heads/${BRANCH_NAME} flutter_version.json
RUN git clone https://github.com/${USER_NAME}/${REPO_NAME}.git -b ${BRANCH_NAME}

# now set the path to flutter and build flutter tool and precache all necessary tools this is good
# because as long as ADD doesn't invalidad these stages we don't have to rebuild this expensive part
ENV PATH="$PATH:/flutter/bin"
RUN flutter precache

# copy the flutter project and change dir into it
COPY . ${WORKDIR}
WORKDIR ${WORKDIR}

# run flutter clean, pub get and then build for web
RUN flutter clean
RUN flutter pub get
RUN flutter build web


# Serve the flutter web app
#
# in the second stage just copy the builded web files from the first
# stage and serve them as static website using basic nginx container
FROM nginx:latest

# setting the workdir
ARG WORKDIR

# tell which port to use (no necessarily needed)
EXPOSE 80

# copy the built flutter static website to the nignx directory
COPY --from=FLUTTER_BUILDER ${WORKDIR}/build/web /usr/share/nginx/html

huangapple
  • 本文由 发表于 2023年3月7日 19:42:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75661539.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定