88echo " === Building Python Docker image with Nix dockerTools ==="
99echo " 🔨 Building secure Docker image with restricted Python environment..."
1010
11- # 清理旧的镜像标签和可能冲突的镜像
11+ # Clean up old image tags and potentially conflicting images
1212echo " 🧹 Cleaning up old image tags and conflicting images..."
13- # 删除目标标签
13+
14+ # First stop and remove containers using docker-python-runner images
15+ echo " 🧹 Cleaning up containers using docker-python-runner images..."
16+ CONTAINERS_TO_STOP=$( docker ps -a --format " {{.ID}} {{.Image}}" | grep " docker-python-runner" | awk ' {print $1}' || echo " " )
17+ if [ -n " $CONTAINERS_TO_STOP " ]; then
18+ echo " Found containers using docker-python-runner images, stopping and removing them..."
19+ echo " $CONTAINERS_TO_STOP " | while read container_id; do
20+ if [ -n " $container_id " ]; then
21+ echo " Stopping container: $container_id "
22+ docker stop " $container_id " 2> /dev/null || echo " Container $container_id already stopped"
23+ echo " Removing container: $container_id "
24+ docker rm " $container_id " 2> /dev/null || echo " Container $container_id already removed"
25+ fi
26+ done
27+ else
28+ echo " No containers using docker-python-runner images found"
29+ fi
30+
31+ # Remove target tag
1432docker rmi ghcr.io/reaslab/docker-python-runner:secure-latest 2> /dev/null || echo " No existing tag to remove"
1533
16- # 清理所有悬空镜像
34+ # Clean up all dangling images
1735echo " 🧹 Cleaning up dangling images..."
1836docker image prune -f 2> /dev/null || echo " No dangling images to remove"
1937
20- # 清理可能冲突的镜像(通过镜像名称识别)
21- echo " 🧹 Cleaning up potentially conflicting images..."
22- # 首先检查是否有ID冲突的镜像
23- CONFLICTING_IMAGES=$( docker images --format " {{.ID}} {{.Repository}}:{{.Tag}}" | awk ' {print $1}' | sort | uniq -d)
24- if [ -n " $CONFLICTING_IMAGES " ]; then
25- echo " Found conflicting image IDs: $CONFLICTING_IMAGES "
26- for conflict_id in $CONFLICTING_IMAGES ; do
27- echo " Removing all tags for conflicting ID: $conflict_id "
28- docker rmi " $conflict_id " 2> /dev/null || echo " Could not remove ID $conflict_id "
29- done
30- fi
31-
32- # 清理Python/UV相关的镜像
33- docker images --format " {{.Repository}}:{{.Tag}} {{.ID}}" | grep -E " (python|uv)" | while read repo_tag id; do
34- if [ " $repo_tag " != " ghcr.io/reaslab/docker-python-runner:secure-latest" ]; then
35- echo " Removing Python/UV related image: $repo_tag ($id )"
36- docker rmi " $id " 2> /dev/null || echo " Could not remove $repo_tag "
37- fi
38+ # Clean up docker-python-runner related images
39+ echo " 🧹 Cleaning up docker-python-runner related images..."
40+ docker images --format " {{.Repository}}:{{.Tag}} {{.ID}}" | grep " docker-python-runner" | while read repo_tag id; do
41+ echo " Removing docker-python-runner image: $repo_tag ($id )"
42+ docker rmi -f " $id " 2> /dev/null || echo " Could not remove $repo_tag "
3843done
3944
4045echo " Building with Nix dockerTools..."
41- # 配置 Nix 以支持 Flakes,与工作流保持一致
46+ # Configure Nix to support Flakes, consistent with workflow
4247mkdir -p ~ /.config/nix
4348cat > ~ /.config/nix/nix.conf << EOF
4449experimental-features = nix-command flakes
4550allow-import-from-derivation = true
4651EOF
4752
48- # 设置环境变量以允许非自由包( Gurobi)
53+ # Set environment variable to allow unfree packages ( Gurobi)
4954export NIXPKGS_ALLOW_UNFREE=1
50- # 使用 nix build 命令,与工作流保持一致
55+
56+ # Generate current UTC timestamp
57+ CURRENT_TIMESTAMP=$( date -u +" %Y-%m-%dT%H:%M:%SZ" )
58+ echo " Setting Docker image timestamp to: $CURRENT_TIMESTAMP "
59+
60+ # Use environment variable to pass timestamp to Nix
61+ export DOCKER_IMAGE_TIMESTAMP=" $CURRENT_TIMESTAMP "
62+
63+ # Use nix build command, consistent with workflow
5164nix build .# docker-image --option sandbox false --impure
5265
5366echo " Loading Nix image into Docker..."
54- # 记录加载前的镜像ID和标签
67+ # Record image IDs and tags before loading
5568BEFORE_IMAGES=$( docker images --format " {{.ID}} {{.Repository}}:{{.Tag}}" | sort)
5669
57- # 加载Nix构建的镜像
70+ # Load Nix-built image
5871docker load < result
5972
60- # 记录加载后的镜像ID和标签
73+ # Record image IDs and tags after loading
6174AFTER_IMAGES=$( docker images --format " {{.ID}} {{.Repository}}:{{.Tag}}" | sort)
6275
6376echo " Tagging image..."
64- # 找出新加载的镜像(通过比较ID和标签)
77+ # Find newly loaded image (by comparing IDs and tags)
6578NEW_IMAGE_INFO=$( comm -13 <( echo " $BEFORE_IMAGES " ) <( echo " $AFTER_IMAGES " ) | head -1)
6679
6780if [ -n " $NEW_IMAGE_INFO " ]; then
6881 NEW_IMAGE_ID=$( echo " $NEW_IMAGE_INFO " | awk ' {print $1}' )
6982 NEW_IMAGE_TAG=$( echo " $NEW_IMAGE_INFO " | awk ' {print $2}' )
7083 echo " Found new image: $NEW_IMAGE_TAG ($NEW_IMAGE_ID )"
7184
72- # 检查是否是我们期望的镜像
85+ # Check if this is our expected image
7386 if [[ " $NEW_IMAGE_TAG " == * " python" * ]] || [[ " $NEW_IMAGE_TAG " == * " uv" * ]] || [[ " $NEW_IMAGE_TAG " == * " reaslab" * ]]; then
7487 echo " Using new image ID: $NEW_IMAGE_ID "
7588 else
7689 echo " New image doesn't match expected pattern, using it anyway"
7790 fi
7891else
7992 echo " No new image detected, checking for existing suitable images"
80- # 查找现有的Python相关镜像
93+ # Find existing Python-related images
8194 EXISTING_PYTHON=$( docker images --format " {{.ID}} {{.Repository}}:{{.Tag}}" | grep -E " (python|uv|reaslab)" | head -1)
8295 if [ -n " $EXISTING_PYTHON " ]; then
8396 EXISTING_ID=$( echo " $EXISTING_PYTHON " | awk ' {print $1}' )
90103 fi
91104fi
92105
93- # 生成标签,与工作流保持一致
106+ # Generate tags, consistent with workflow
94107TIMESTAMP=$( date +%Y%m%d-%H%M%S)
95108SHORT_SHA=$( git rev-parse --short HEAD 2> /dev/null || echo " local" )
96109
@@ -99,18 +112,20 @@ echo " - ghcr.io/reaslab/docker-python-runner:secure-latest"
99112echo " - ghcr.io/reaslab/docker-python-runner:secure-$TIMESTAMP "
100113echo " - ghcr.io/reaslab/docker-python-runner:secure-$SHORT_SHA "
101114
102- # 创建多个标签,与工作流保持一致
115+ # Create multiple tags, consistent with workflow
103116docker tag $NEW_IMAGE_ID ghcr.io/reaslab/docker-python-runner:secure-latest
104117docker tag $NEW_IMAGE_ID ghcr.io/reaslab/docker-python-runner:secure-$TIMESTAMP
105118docker tag $NEW_IMAGE_ID ghcr.io/reaslab/docker-python-runner:secure-$SHORT_SHA
106119
107- # 验证最终镜像状态
120+ # Verify final image state
108121echo " 🔍 Verifying final image state..."
109122FINAL_IMAGE_ID=$( docker images --format " {{.ID}}" ghcr.io/reaslab/docker-python-runner:secure-latest 2> /dev/null || echo " " )
110123if [ -n " $FINAL_IMAGE_ID " ]; then
111124 echo " Final image ID: $FINAL_IMAGE_ID "
125+ echo " Created: $( docker images --format " {{.CreatedAt}}" ghcr.io/reaslab/docker-python-runner:secure-latest) "
126+ echo " Size: $( docker images --format " {{.Size}}" ghcr.io/reaslab/docker-python-runner:secure-latest) "
112127
113- # 检查是否有其他镜像使用相同的ID
128+ # Check if other images use the same ID
114129 DUPLICATE_TAGS=$( docker images --format " {{.Repository}}:{{.Tag}} {{.ID}}" | awk -v target_id=" $FINAL_IMAGE_ID " ' $2 == target_id && $1 != "ghcr.io/reaslab/docker-python-runner:secure-latest" {print $1}' )
115130
116131 if [ -n " $DUPLICATE_TAGS " ]; then
130145echo " ✅ Build completed successfully!"
131146
132147echo " 📋 Secure Image Configuration:"
133- echo " - Python version : 3.12 (restricted environment)"
148+ echo " - Python Version : 3.12 (restricted environment)"
134149echo " - Security: Dangerous modules blocked (os, subprocess, sys, etc.)"
135- echo " - Resource limits : 1GB memory, CPU shares limit "
136- echo " - Safe packages : pip, setuptools, wheel, cython, numpy, scipy, pandas, matplotlib, scikit-learn"
150+ echo " - Resource Limits : 1GB memory, CPU share limits "
151+ echo " - Safe Packages : pip, setuptools, wheel, cython, numpy, scipy, pandas, matplotlib, scikit-learn, yfinance, seaborn "
137152echo " - Gurobi: 12.0.3 (via nixpkgs)"
138- echo " - Container: Read-only rootfs , non-root user (1000:1000)"
153+ echo " - Container: Read-only root filesystem , non-root user (1000:1000)"
139154echo " - Network: Restricted (disabled by default)"
140155echo " - Tools: Minimal set (bash, coreutils, curl, tar, gzip)"
141- echo " - Compilation tools: Removed for security"
156+ echo " - Compilation Tools: Removed for security"
157+ echo " - Module Installation: Support via UV installation to /tmp/.local/lib/python3.12/site-packages"
142158echo " Image: ghcr.io/reaslab/docker-python-runner:secure-latest"
0 commit comments