Poniżej dzielę się moją metodą na uruchomienie kilku linuxowych maszyn wirtualnych oraz dowolnych kontenerów Dockera wewnątrz tych maszyn – to wszystko w telefonie z systemem Android.
Oficjalnie docker dla Androida nie działa z powodu specyfiki androidowego krenela, ale można potestować Dockera w wirtualnej maszynie. Efekty pracy kontenerów można oglądać bezpośrednio w Androidzie, dzięki podwójnemu przekierowaniu portów – z kontenera do maszyny wirtualnej a następnie z maszyny wirtualnej do Androida. Rozwiązane jest oparte na programie do wirtualizacji i emulacji Limbo x86 PC Emulator, który to program z kolei jest oparty na QEMU. W Limbo (bez wsparcia KVM) bardzo responsywnie pracuje Alpine Linux, który posłuży nam jako host Dockera.
Instalacja Limbo x86 PC Emulator
W pierwszej kolejności instalujemy program Limbo x86 i w nim lekką dystrybucję Alpine Linux w wersji x86_64 (grupa VIRTUAL) – wykorzystując poniższe ustawienia maszyny wirtualnej:

Naciśnij tutaj, aby rozwinąć grafikę
Należy zwrócić szczególną uwagę na linię przekierowującą porty maszyny wirtualnej na Androida (ssh oraz poszczególnych serwerów WWW):
hostfwd=tcp::10022-:22,hostfwd=tcp::8080-:80,hostfwd=tcp::8081-:8081,hostfwd=tcp::8082-:8082
Film
Nim przejdziemy do instalacji Dockera poniżej krótki filmik przedstawiający to rozwiązanie. Prezentuję uruchomienie maszyny wirtualnej Alpine w Limbo X86, uruchamianie kontenerów Dockera, testowanie pod Androidem zkonteneryzowanych tak serwerów WWW, uruchamianie dodatkowej maszyny wirtualnej z Debianem na ARM-owej wersji Limbo, łączenie się wirtualnej maszyny w Limbo x86 z maszyną w Limbo ARM, łączenie się z serwerem SSH kontenera z zewnętrznego komputera:
Instalacja Dockera
Po dostosowaniu Alpine do swoich potrzeb dodajemy do pliku /etc/apk/repositories jedną linię poniższym poleceniem:
echo 'http://dl-cdn.alpinelinux.org/alpine/latest-stable/community' >> /etc/apk/repositories
następnie wpisujemy:
apk update
apk add docker wget
service docker start
Docker działa poprawnie jeżeli w wyniku poniższego polecenia wyświetli się wersja serwera:
docker info | grep rver
Jeżeli docker wystartuje, to możemy dodać go do uruchamiania wraz z systemem
rc-update add docker boot
Jeżeli jednak z powodu ograniczeń telefonu lub tabletu Docker się nie uruchomi jako usługa (jak w moim przypadku), to należy skorzystać z mojego obejścia tworząc poniższy plik uruchomieniowy:
service cgroups start sleep 5 rm /var/run/docker.pid 2> /dev/null rm /var/run/docker.sock 2> /dev/null containerd >> /var/log/containerd.log 2>&1 & sleep 15 dockerd --dns 8.8.8.8 --mtu=1500 >> /var/log/docker.log 2>&1 &
Ponieważ jest to również przyspieszony kurs Dockera, to dla lepszego zobrazowania ograniczymy się do podstawowych funkcji tego narzędzia. Po wcześniejszym zabezpieczeniu polecam wyłączenie demona ssh i logowanie się przez telnet, co nieco odciąży urządzenie (telned jest zawarty w Alpine w paczce busybox-extras).
Dodajemy grupę docker i dołączamy swojego użytkownika do tej grupy:
addgroup docker -g 101
adduser nazwa_użytkownika docker
Od tej pory możemy pracować z Dockerem bez używania konta roota – w wersjach produkcyjnych Dockera zalecane jest jednak korzystanie z polecenia sudo i pominięcie tego kroku.
Instalacja kontenerów
Pobieramy najnowszy image Debiana:
docker pull debian
Jeżeli pobieranie zakończy się komunikatem: TLS handshake timeout, to do parametrów uruchamiania dockerd dodajemy jeszcze:
--registry-mirror=http://f2d6cb40.m.daocloud.io
Uruchamiamy kontener, instalujemy serwer lighttpd i opuszczamy kontener:
docker run --name=www_srv -it ubuntu bash
apt update
apt install lighttpd
exit
Zatrzymujemy kontener, zapisujemy jego image, sprawdzamy czy nowy obraz zapisał się poprawnie i usuwamy zbędny kontener:
docker stop www_srv
docker commit www_srv www_srv
docker images
docker rm www_srv
W celu uporządkowania adresów IP tworzymy oddzielną sieć dla Dockera:
docker network create --subnet=172.18.0.0/16 dockernet
Sprawdzamy sieci:
docker network ls
Tworzymy współdzielone katalogi (busyboxowa wersja mkdir jest bardzo uproszczona i nie pozwala na używanie list):
mkdir -p ~/www/srv_1 && mkdir ~/www/srv_2
W katalogach tych umieszczamy dokument index.html – ja umieściłem placeholdery lighttpd, tylko zmieniłem im tyluł, aby łatwo było identyfikować ich pochodzenie w późniejszych testach.
Do testów instalujemy lighttpd również na wirtualce.
Przypisujemy port 80 kontenerów do portów 8081 i 8082 wirtualki oraz dyskową przestrzeń współdzieloną, a następnie uruchamiamy kontenery w tle i serwery lighttpd:
docker run --net dockernet -v ~/www/srv_1:/var/www/html --ip 172.18.0.3 --name=www_srv_1 -p 8081:80 -dit www_srv bash
docker run --net dockernet -v ~/www/srv_2:/var/www/html --ip 172.18.0.4 --name=www_srv_2 -p 8082:80 -dit www_srv bash
for i in 1 2; do docker exec www_srv_${i} service lighttpd start; done
Sprawdzamy procesy w uruchomionym kontenerze:
docker top www_srv_1
W celu inspekcji lub doinstalowania dodatkowego oprogramowania, możemy wejść do uruchomionego kontenera poleceniem:
docker exec -ti www_srv_1 bash
Możemy już uruchomić przeglądarkę WWW w Androidzie i sprawdzić jak wygląda strona http://localhost na portach od 8080 do 8082.
Szybkość działania
Jeżeli urządzenie z Androidem posiada jądro skompilowane ze wsparciem dla KVM, to prędkość działania będzie zbliżona do pracy maszyny wirtualnej na średniej klasy komputerze PC (o ile wirtualny system będzie zgodny z architekturą urządzenia) – wtedy też Limbo zapewnia prawdziwą wirtualizację zasobów. Jeżeli wsparcia brak, to Limbo przejdzie w tryb emulacji, który jest dużo wolniejszy, ale przy silnym androidowym urządzeniu nadal o akceptowalnej wydajności i responsywności. Jeżeli telefon lub tablet są wiekowe (lub tzw. wersją ekonomiczną), to Limbo można wykorzystać już tylko do zabawy z Alpine Linux (bez Dockera) lub ze starszymi wersjami Debiana.
Podsumowanie
Moje urządzenie (Gemini PDA) nie zwiera wsparcia dla KVM, ale i tak w połączeniu z Alpine, Dockerem i odrobiną cierpliwości Limbo jest użytecznym oprogramowaniem. Im silniejsze urządzenie z Androidem, tym szybciej Limbo działa również w tym standardowym trybie emulacji. Program wymaga, by wszystkie obrazy były umieszczone na karcie pamięci. W trybie SDL renderowanie grafiki jest szybsze, ale aplikacja nie działa w tle. W trybie VNC renderowanie jest wolniejsze (co nie jest taki istotne w przypadku CLI), ale Limbo (i co za tym idzie – wirtualna maszyna) działa w tle nawet po wyłączeniu telefonu czy tabletu. Jeżeli nie chcemy oczekiwać na długie uruchomienie emulowanego systemu, to wirtualną maszynę można pauzować – wznowienie jej pracy zajmuje tylko kilka sekund. Docker na telefonie sprawdza się w prostych zastosowaniach programistycznych i administracyjnych. Polecam.
Więcej informacji o Limbo można znaleźć na stronie GitHub projektu oraz na nieistniejącej już oficjalnej stronie emulatora (w web.archive.org).