这是indexloc提供的服务,不要输入任何密码
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 50 additions & 38 deletions .github/workflows/docker_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,52 @@ env:
DOCKER_BUILDKIT: 1

jobs:
main:
runs-on: ubuntu-latest
generate:
strategy:
matrix:
CPU_ARCH:
- aarch64
- arm
- i686
- x86_64
include:
- runner: ubuntu-24.04
architecture: i686
package-manager: apt
- runner: ubuntu-24.04
architecture: x86_64
package-manager: apt
- runner: ubuntu-24.04-arm
architecture: arm
package-manager: apt
- runner: ubuntu-24.04-arm
architecture: aarch64
package-manager: apt
- runner: ubuntu-24.04
architecture: i686
package-manager: pacman
- runner: ubuntu-24.04
architecture: x86_64
package-manager: pacman
- runner: ubuntu-24.04-arm
architecture: arm
package-manager: pacman
- runner: ubuntu-24.04-arm
architecture: aarch64
package-manager: pacman
runs-on: ${{ matrix.runner }}
steps:

- name: Set variables
run: |
echo "TERMUX_ARCH=${{ matrix.architecture }}" >> $GITHUB_ENV
echo "TERMUX_PACKAGE_MANAGER=${{ matrix.package-manager }}" >> $GITHUB_ENV
if [ ${{ matrix.package-manager }} = apt ]; then
echo "TERMUX_DOCKER__IMAGE_NAME=termux/termux-docker" >> $GITHUB_ENV
elif [ ${{ matrix.package-manager }} = pacman ]; then
echo "TERMUX_DOCKER__IMAGE_NAME=termux/termux-docker-pacman" >> $GITHUB_ENV
fi

- name: Clone repository
uses: actions/checkout@v4

- name: Setup binfmt_misc
if: (matrix.CPU_ARCH == 'aarch64') || (matrix.CPU_ARCH == 'arm')
run: docker run --rm --privileged aptman/qus -s -- -p aarch64 arm

- name: Build images
run: |
case '${{ matrix.CPU_ARCH }}' in
arm) SYSTEM_TYPE=arm; PLATFORM_TAG="linux/arm/v7";;
aarch64) SYSTEM_TYPE=arm; PLATFORM_TAG="linux/arm64";;
i686) SYSTEM_TYPE=x86; PLATFORM_TAG="linux/386";;
*) SYSTEM_TYPE=x86; PLATFORM_TAG="linux/amd64";;
esac
docker buildx build -t \
termux/termux-docker:${{ matrix.CPU_ARCH }} \
--platform "$PLATFORM_TAG" \
--build-arg BOOTSTRAP_ARCH=${{ matrix.CPU_ARCH }} \
--build-arg SYSTEM_TYPE="${SYSTEM_TYPE}" \
.
- name: Build image
run: ./generate.sh

- name: Login to Docker Hub
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'termux/termux-docker'
Expand All @@ -57,28 +71,26 @@ jobs:
- name: Push to Docker Hub
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'termux/termux-docker'
run: |
docker push termux/termux-docker:${{ matrix.CPU_ARCH }}
if [ ${{ matrix.CPU_ARCH }} = i686 ]; then
docker tag termux/termux-docker:i686 termux/termux-docker:latest
docker push termux/termux-docker:latest
docker push ${{ env.TERMUX_DOCKER__IMAGE_NAME }}:${{ env.TERMUX_ARCH }}
if [ ${{ env.TERMUX_ARCH }} = x86_64 ]; then
docker push ${{ env.TERMUX_DOCKER__IMAGE_NAME }}:latest
fi

- name: Export container as tar archive
if: always()
run: |
docker run \
--privileged \
--name termux-docker-${{ matrix.CPU_ARCH }} \
termux/termux-docker:${{ matrix.CPU_ARCH }} \
--name termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }} \
${{ env.TERMUX_DOCKER__IMAGE_NAME }}:${{ env.TERMUX_ARCH }} \
uname -a
docker stop termux-docker-${{ matrix.CPU_ARCH }}
docker export -o termux-docker-${{ matrix.CPU_ARCH }}.tar \
termux-docker-${{ matrix.CPU_ARCH }}
sha256sum termux-docker-${{ matrix.CPU_ARCH }}.tar
docker stop termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}
docker export -o termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}.tar \
termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}
sha256sum termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}.tar

- name: Store tar archive
if: always()
uses: actions/upload-artifact@v4
with:
name: termux-docker-${{ matrix.CPU_ARCH }}-${{ github.sha }}
path: termux-docker-${{ matrix.CPU_ARCH }}.tar
name: termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}-${{ github.sha }}
path: termux-docker-${{ env.TERMUX_PACKAGE_MANAGER }}-${{ env.TERMUX_ARCH }}.tar
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
termux-docker-rootfs
131 changes: 57 additions & 74 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,73 @@
# Bootstrap Termux environment.
FROM scratch AS bootstrap

ARG BOOTSTRAP_VERSION=2023.02.19-r1%2Bapt-android-7
ARG BOOTSTRAP_ARCH=i686
ARG SYSTEM_TYPE=x86
ARG TERMUX_DOCKER__ROOTFS
ARG TERMUX__PREFIX
ARG TERMUX__CACHE_DIR

# Docker uses /bin/sh by default, but we don't have it currently.
SHELL ["/system/bin/sh", "-c"]
ENV PATH /system/bin
# Install generated rootfs containing:
# - termux bootstrap
# - aosp-libs (bionic libc, linker, boringssl, zlib, libicuuc, debuggerd)
# - aosp-utils (toybox, mksh, iputils)
# - libandroid-stub
# - dnsmasq
# Since /system is now a symbolic link to $PREFIX/opt/aosp,
# which has contents that can be updated by the system user via apt,
# the entire rootfs is now owned by the system user (1000:1000).
COPY --chown=1000:1000 ${TERMUX_DOCKER__ROOTFS} /

# Copy libc, linker and few utilities.
COPY /system/$SYSTEM_TYPE /system
# Docker uses /bin/sh by default, but we don't have it.
ENV PATH=/system/bin
SHELL ["sh", "-c"]

# Copy entrypoint script.
COPY /entrypoint.sh /entrypoint.sh
COPY /entrypoint_root.sh /entrypoint_root.sh

# Extract bootstrap archive and create symlinks.
ADD https://github.com/termux/termux-packages/releases/download/bootstrap-$BOOTSTRAP_VERSION/bootstrap-$BOOTSTRAP_ARCH.zip /bootstrap.zip
RUN busybox mkdir -p /data/data/com.termux/files && \
cd /data/data/com.termux/files && \
busybox mkdir ../cache ./usr ./home && \
busybox unzip -d usr /bootstrap.zip && \
busybox rm /bootstrap.zip && \
cd ./usr && \
busybox cat SYMLINKS.txt | while read -r line; do \
dest=$(echo "$line" | busybox awk -F '←' '{ print $1 }'); \
link=$(echo "$line" | busybox awk -F '←' '{ print $2 }'); \
busybox ln -s "$dest" "$link"; \
done && \
busybox rm SYMLINKS.txt && \
busybox ln -s /data/data/com.termux/files/usr /usr && \
busybox ln -s /data/data/com.termux/files/usr/bin /bin && \
busybox ln -s /data/data/com.termux/files/usr/tmp /tmp

# Link some utilities to busybox.
# Some utilities in $PREFIX are actually a wrapper of the same binary
# from /system/bin. See termux-tools/build.sh#L29.
RUN for tool in df mount ping ping6 su top umount; do \
busybox ln -s /system/bin/busybox /system/bin/$tool; \
done

# Set ownership and file access modes:
# * User content is owned by 1000:1000.
# * Termux file modes are set only for user.
# * Rest is owned by root and has 755/644 modes.
RUN busybox chown -Rh 0:0 /system && \
busybox chown -Rh 1000:1000 /data/data/com.termux && \
busybox ln -s /system/etc/passwd /etc/passwd && \
busybox ln -s /system/etc/group /etc/group && \
busybox find /system -type d -exec busybox chmod 755 "{}" \; && \
busybox find /system -type f -executable -exec busybox chmod 755 "{}" \; && \
busybox find /system -type f ! -executable -exec busybox chmod 644 "{}" \; && \
busybox find /data -type d -exec busybox chmod 755 "{}" \; && \
busybox find /data/data/com.termux/files -type f -o -type d -exec busybox chmod g-rwx,o-rwx "{}" \; && \
cd /data/data/com.termux/files/usr && \
busybox find ./bin ./lib/apt ./libexec -type f -exec busybox chmod 700 "{}" \;

# Install updates and cleanup when not building for arm.
ENV PATH /data/data/com.termux/files/usr/bin
RUN if [ ${SYSTEM_TYPE} = 'arm' ]; then exit; else \
/system/bin/mksh -T /dev/ptmx -c "/system/bin/dnsmasq -u root -g root --pid-file /dnsmasq.pid" && sleep 1 && \
su - system -c "/data/data/com.termux/files/usr/bin/apt update" && \
su - system -c "/data/data/com.termux/files/usr/bin/apt upgrade -o Dpkg::Options::=--force-confnew -yq" && \
rm -rf /data/data/com.termux/files/usr/var/lib/apt/* && \
rm -rf /data/data/com.termux/files/usr/var/log/apt/* && \
rm -rf /data/data/com.termux/cache/apt/* ;\
fi
# Install updates and cleanup
# Start dnsmasq to resolve hostnames, and,
# for some reason the -c argument of toybox-su is not working,
# so this odd-looking script forces the update process
# to work using the -s argument of toybox-su instead, which is working.
RUN sh -T /dev/ptmx -c "$TERMUX__PREFIX/bin/dnsmasq -u root -g root --pid-file=/dnsmasq.pid" && \
sleep 1 && \
echo '#!/system/bin/sh' > /update.sh && \
echo "PATH=$TERMUX__PREFIX/bin" >> /update.sh && \
echo "source $TERMUX__PREFIX/bin/termux-setup-package-manager" >> /update.sh && \
echo 'if [ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" ]; then' >> /update.sh && \
echo 'apt update' >> /update.sh && \
echo 'apt upgrade -o Dpkg::Options::=--force-confnew -y' >> /update.sh && \
echo 'elif [ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" ]; then' >> /update.sh && \
echo 'pacman-key --init' >> /update.sh && \
echo 'pacman-key --populate' >> /update.sh && \
echo 'pacman -Syyu --noconfirm' >> /update.sh && \
echo 'fi' >> /update.sh && \
chmod +x /update.sh && \
su system -s /update.sh && \
rm -rf /update.sh \
"${TERMUX__PREFIX}"/var/lib/apt/* \
"${TERMUX__PREFIX}"/var/log/apt/* \
"${TERMUX__CACHE_DIR}"/apt/* \
"${TERMUX__PREFIX}"/var/cache/pacman/pkg/* \
"${TERMUX__PREFIX}"/var/log/pacman.log

##############################################################################
# Create final image.
FROM scratch

ENV ANDROID_DATA /data
ENV ANDROID_ROOT /system
ENV HOME /data/data/com.termux/files/home
ENV LANG en_US.UTF-8
ENV PATH /data/data/com.termux/files/usr/bin
ENV PREFIX /data/data/com.termux/files/usr
ENV TMPDIR /data/data/com.termux/files/usr/tmp
ENV TZ UTC
ARG TERMUX__PREFIX
ARG TERMUX__HOME

ENV ANDROID_DATA=/data
ENV ANDROID_ROOT=/system
ENV HOME=${TERMUX__HOME}
ENV LANG=en_US.UTF-8
ENV PATH=${TERMUX__PREFIX}/bin
ENV PREFIX=${TERMUX__PREFIX}
ENV TMPDIR=${TERMUX__PREFIX}/tmp
ENV TZ=UTC
ENV TERM=xterm

COPY --from=bootstrap / /

WORKDIR /data/data/com.termux/files/home
SHELL ["/data/data/com.termux/files/usr/bin/sh", "-c"]
WORKDIR ${TERMUX__HOME}
SHELL ["sh", "-c"]

ENTRYPOINT ["/entrypoint.sh"]
CMD ["/data/data/com.termux/files/usr/bin/login"]
CMD ["login"]
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ normal Termux installation.
docker run -it termux/termux-docker:latest
```

When using the tag `latest`, container will be 32 bit (i686 architecture).
When using the tag `latest`, container will be 64 bit (x86_64 architecture).

Other architecture can be installed using a different tags. Available
tags:

- `aarch64`
- `arm`
- `i686` (`latest`)
- `x86_64`
- `i686`
- `x86_64` (`latest`)

If architecture is not compatible with host, the additional setup will
be needed. Read this document further to learn how you can run containers
Expand All @@ -39,7 +39,7 @@ of incompatible CPU architecture.
The initial user of container must be root. Otherwise DNS will be broken
because of `dnsmasq` server failure.

### Running ARM containers on x86 host
### Running ARM containers

In order to run AArch64 container on x86(64) host, you need to setup
QEMU emulator through binfmt_misc. This can be easily done by one
Expand All @@ -49,9 +49,12 @@ command:
docker run --rm --privileged aptman/qus -s -- -p aarch64 arm
```

Note that AArch64 and ARM containers work properly only in privileged
mode. If you want your containers to have standard privileges, a custom
seccomp profile is required.
Note that AArch64 and ARM containers sometimes work properly only in privileged
mode, even on some real ARM devices. If you want your containers to have standard privileges, a custom
seccomp profile or a custom build of Docker might be required. The custom build
of Docker limits the customizations to purely what is necessary for
the `personality()` system call, leaving the security settings of all other system
calls untouched.

Variant with privileged container:

Expand All @@ -65,6 +68,25 @@ Variant with seccomp unconfined profile:
docker run -it --security-opt seccomp:unconfined termux/termux-docker:aarch64
```

Variant with custom build of Docker:

> [!NOTE]
> Example with Debian trixie `armhf` host and the `docker.io` package. Assumes that [`deb-src` URIs](https://wiki.debian.org/Packaging/SourcePackage?action=show&redirect=SourcePackage#With_apt-get_source) and the [`devscripts` package](https://wiki.debian.org/Packaging#Suggested_tools_to_create_an_environment_for_packaging) are already installed, and that the current user is a member of the `docker` group.

```.sh
sudo apt build-dep docker.io
apt source docker.io
cp /path/to/termux-docker/custom-docker-with-unrestricted-personality.patch docker.io-*/debian/patches/
echo 'custom-docker-with-unrestricted-personality.patch' >> docker.io-*/debian/patches/series
cd docker.io-*/
DEB_BUILD_OPTIONS=nocheck debuild -b -uc -us
rm ../golang*
sudo apt install ../*.deb
docker run -it termux/termux-docker:arm
```

You might then want to temporarily use `sudo apt-mark hold docker.io` to ensure the package is not automatically upgraded, causing termux-docker to stop working on the device in the future, but **not upgrading can be a security risk**. If using the patch, it is recommended to patch and recompile the Docker daemon after every upgrade.

### Non-interactive execution of commands

You can run commands in non-interactive mode. Just append them to Docker
Expand Down Expand Up @@ -99,20 +121,20 @@ docker run -it --entrypoint /entrypoint_root.sh termux/termux-docker:latest
Docker:

```.sh
./build-all.sh
./generate.sh
```

Podman:

```.sh
./build-all.sh --podman
./generate.sh --podman
```

## Known issues

There a number of known issues which may not be resolved:

* ARM containers may require a custom seccomp profile to remove restrictions from
* ARM containers might require a custom seccomp profile or custom build of Docker to remove restrictions from the
`personality()` system call.

* When running certain multi threaded program in 32bit containers, the PIDs can
Expand Down
Loading