Flutter Integration Test Server in Debian 11 Nspawn Container
date: 2021-09-24
Introduction
Performance
Your Debian Server is way more powerful than your laptop or desktop and flutter integration_tests suck.
Ergonomics
You have an Android Emulator (or a real device) connected to the machine that you are sitting in front of for reference, and now you can run integration_tests on a different device without having to juggle adb connections on the same machine.
Nspawn Tho?
Because containers unlike virtual machines access the full power of the host, but nspawn containers are peristent like virtual machines, sparing you the cognitive overhead of dealing with the ephemerality of docker containers and/or of herding cats.
And you already have nspawn, it's build into systemd. Even including the (virtual) network interfaces.
Documentation
Let's face it: setting up an Android Development Environment is a nightmare.
So don't just follow this guide; follow this guide a repetition of three times, building your own step-by-step for yourself as you go. Your brain will thank you.
Host Preparation (Debian 11)
- install
systemd-container
anddebootstrap
- enable unprivileged user namespaces
echo 'kernel.unprivileged_userns_clone=1' >/etc/sysctl.d/nspawn.conf
systemctl restart systemd-sysctl.service
- you might as well allow debootstrap to user your apt-cacher-ng proxy
export http_proxy=http://<ip address>:3142
br0 bridge
describe br0 bridge in /etc/systemd/nspawn/ftest.nspawn
(optional).
# /etc/systemd/nspawn/ftest.nspawn
[Network]
VirtualEthernet=yes
Bridge=br0
ZFS mountpoint
This is optional, obviously; you might not even use zfs.
zfs create vm_pool/nspawn/ftest
zfs set mountpoint=/var/lib/machines/ftest vm_pool/nspawn/ftest
- sanity check
zfs list -r vm_pool/nspawn
bootstrap container
# for apt-cacher-ng proxy
export http_proxy=http://<ip address>:3142
debootstrap --include=systemd-container stable /var/list/machines/ftest
preboot config
- delete container's package cache
- copy
/etc/apt/apt.conf
to container - copy
/root/.bashrc
to container - copy
/root/.inputrc
to container - edit
/etc/hostname
in container - write nspawn file on host
- copy
/etc/locale.gen
to/etc/locale.gen.bak
on container
first interactive boot
systemd-nspawn -D /var/lib/machines/ftest -U --machine ftest
- set passwd:
passwd
- stop container:
logout
run as service
systemctl start systemd-nspawn@ftest
- login:
machinectl login ftest
- start/enable network
systemctl enable --now systemd-networkd
- add regular user
useradd <username>
install applications
locale
- install locales
- edit
/etc/locale.gen
to taste and then run the commandlocale-gen
essential apps
apt-get install openssh-server git unzip wget sudo curl file rsync
add regular user to sudo group
usermod -a -G sudo <user>
other apps
apt-get install mosh htop haveged byobu needrestart tree bash-completion
install openjdk-8 from stretch repo
- add following to
/etc/apt/sources.list
deb http://security.debian.org/debian-security stretch/updates main
apt-get update && apt-get install openjdk-8-jdk-headless
user environment
You can now ssh into your container.
scp your favorite environment files over to the container
- ~/.byobu/
- ~/.bashrc
- ~/.bash_aliases
- ~/.inputrc
install flutter
Pick a location to taste; I prefer ~/.local/
cd ; cd .local
git clone https://github.com/flutter/flutter.git
downgrade flutter
if needed:
cd ~/.local/flutter
git checkout 2.2.3
install command-line-tools
The schuck and jive here is absurd, but here goes.
Now is the time to decide where ANDROID_HOME and ANDROID_SDK_ROOT
are going to be; I prefer ~/.local/share/Android/Sdk/
mkdir -p ~/.local/share/Android/Sdk
temporary installation of cmdline-tools
Command line tools only Scroll half way down
cd ~/.local/share/Android/Sdk
wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip
unzip commandlinetools-linux-7583922_latest.zip
mkdir 5.0
mv cmdline-tools/* 5.0/
mv 5.0 cmdline-tools/
flutter and sdk environment
add the following to ~/.bashrc
function addToPATH {
case ":$PATH:" in
*":$1:"*) :;; # already there
*) PATH="$PATH:$1";; # or PATH="$PATH:$1"
esac
}
addToPATH ~/.local/flutter/bin
addToPATH ~/.local/share/Android/Sdk/cmdline-tools/latest/bin
addToPATH ~/.local/share/Android/Sdk/platform-tools
# temporary path to temporary version of cmdline-tools
addToPATH ~/.local/share/Android/Sdk/cmdline-tools/5.0/bin
add the following to ~/.bash_aliases
alias sdkmanager='sdkmanager --sdk_root=~/.local/share/Android/Sdk'
Confirm by logging out and then back in and:
which flutter ; which sdkmanager ; alias
now install cmdline-tools for real
sdkmanager --install "cmdline-tools;latest"
and then logout and log back in
cleanup
At this point I think you can remove or comment the temporary PATH
statement from ~/.bashrc
for the temporary location of cmdline-tools
install Android SDK
review your options
sdkmanager --list
sdkmanager --install "platforms;android-30" \
"build-tools;31.0.0" "build-tools;30.0.3"
confirm flutter installation
flutter doctor
run tests
At this point you shoud be able to rsync a flutter app over to the container, connect to a device using network adb, and run something like:
flutter drive --driver integration_test/driver.dart \
--target integration_test/app_test.dart --profile