Alpine Podman image

精简 Alpine Linux 的开发环境

精简的alpine开发环境
# Use latest Alpine
FROM alpine:latest

RUN apk update && apk upgrade

# Devops utilities
RUN apk add --no-cache openssh openssl bind-tools tmux git neovim

# install system core tools and build-base (C/C++, gdb, compile dependence)
RUN apk add --no-cache \
    tini \
    su-exec \
    bash \
    git \
    curl \
    doas \
    build-base \
    gdb \
    cmake \
    linux-headers

# install language develop env
# Python, Node.js, Go
RUN apk add --no-cache \
    python3 \
    py3-pip \
    nodejs \
    npm \
    go

# install Rust
RUN apk add --no-cache rust cargo

# create admin (UID/GID 1000)
ARG USER=admin
ARG GROUP=admin
ARG UID=1000
ARG GID=1000

RUN addgroup -g ${GID} ${GROUP} && \
    adduser -u ${UID} -G ${GROUP} -s /bin/bash -D ${USER} && \
    echo "permit nopass :${GROUP}" > /etc/doas.d/doas.conf

# develop enviroment
# Go PATH
ENV GOPATH=/home/${USER}/go
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
# Rust Cargo bin PATH
ENV PATH=$PATH:/home/${USER}/.cargo/bin

# WorkSpace
WORKDIR /workspace
RUN chown ${USER}:${GROUP} /workspace

# Entrypoint
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/sbin/tini", "--", "/entrypoint.sh"]

CMD ["/bin/bash"]

其中 entrypoint.sh 脚本如下:

entrypoint.sh 提供对Docker环境进行修正
#!/bin/bash

# get HOST UID/GID dynamic (inject by env, default is 1000)
USER_ID=${NEW_UID:-1000}
GROUP_ID=${NEW_GID:-1000}

# if UID changed, fix admin's ID in container
if [ "$USER_ID" != "1000" ]; then
    echo "Updating admin UID to $USER_ID..."
    sed -i "s/^admin:x:1000:1000:/admin:x:$USER_ID:$GROUP_ID:/" /etc/passwd
    sed -i "s/^admin:x:1000:/admin:x:$GROUP_ID:/" /etc/group
fi

# WorkSpace owner right( podman can do it, so remove)
#CURRENT_OWNER=$(stat -c '%u' /workspace)
#if [ "$CURRENT_OWNER" != "$USER_ID" ]; then
#    echo "Adjusting permissions for /workspace..."
#    chown -R admin:admin /workspace
#fi

# switch to admin, then run commands
# using exec to confirm signal has been forward to sub process
# exec su-exec admin "$@" REPORT ERROR => su-exec: setgroups: Operation not permitted
exec doas -u admin "$@"

构建镜像:

构建镜像
podman build --rm -t alpine-dev .

然后再运行:

运行podman
podman run -d \
  --name alpine-dev-toolkit \
  --hostname alpine-dev-toolkit \
  -p 8080:8080 \
  -p 8443:8443 \
  -p 9000:9000 \
  --user 1000:1000 \
  --userns keep-id \
  -e LANG=C.UTF-8 \
  --workdir /workspace \
  -v /home/admin/docs:/workspace:z \
  -v admin_home_data:/home/admin \
  -v /home/admin/.ssh:/home/admin/.ssh \
  --cap-add SYS_PTRACE \
  --security-opt seccomp=unconfined \
  localhost/alpine-dev_dev-env \
  sh -c "sleep infinity"

docker compose运行

为了方便构建,采用 docker compose 来启动容器,即创建 docker-compose.yml :

docker-compose.yml
version: '3.8'

services:
  dev-env:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: alpine-dev-toolkit

    # use UID Alias map (if userns_mode: "keep-id" ERROR, you can use this underlayer map)
    user: "1000:1000"                            # force container admin

    # force admin
    # user: "admin"
    # Podman special: keep HOST UID same as Container
    # if podman-compose report error, please startup with --pod=no
    userns_mode: "keep-id"
    # override Docker images entrypoint
    entrypoint: ["/bin/sh", "-c", "sleep infinity"]

    environment:
      # when use Podman Rootless, 1000 in container always mapped to HOST's current user
      # so we do not need NEW_UID, but remain 
      - NEW_UID=1000
      - NEW_GID=1000
      - LANG=C.UTF-8
      - TZ=Asia/Shanghai
      #- MY_PROJECT_MODE=debug

    volumes:
      # persistence admin's home directory(include languages cache, config, ssh key, etc)
      # "container_home_data" is HOST "~/.local/share/containers/storage/volumes/container_home_data/_data"
      - admin_home_data:/home/admin

      # :Z means Podman automatic fix SELinux/Ownership
      # :U means remap Host directory ownership to Container User, not need chown (Magic)
      # :z means Podman mount direcoty can be shared by many containers
      - /home/admin/docs:/workspace:rw,z

      # special config map
      - ~/.ssh/id_rsa:/home/admin/.ssh/id_rsa:ro,z
      - ~/.gitconfig:/home/admin/.gitconfig:ro,z
    
    # debug and permit
    cap_add:
      - SYS_PTRACE        # allow GDB debug
    security_opt:
      # Podman have many limits, so we need disable "seccomp" to permit GDB
      - seccomp:unconfined # disable security compute limit
      # if Alpine use SELinux, need following line:
      - label=disable
    
    # keep container run in background
    stdin_open: true
    tty: true

volumes:
  # define persistent home directory
  admin_home_data:

然后执行:

运行 docker compose`
docker compose -d .