
# 构建沙箱镜像
AgentSphere沙箱通过内置的ENVD（环境守护进程，Environment Daemon）来提供文件操作、进程管理和环境变量设置等能力。
由于当前沙箱仅支持单容器部署，ENVD需要作为容器内的常驻进程运行，因此您需要基于自己的业务镜像进行自定义构建，将ENVD集成到镜像中。
#### 前提条件
- 已安装Docker用于构建镜像。
- 已安装Go语言编译环境，用于编译ENVD二进制，版本建议1.21+。
- 已准备好需要作为基础的业务镜像。
- 已有SWR镜像仓库，构建完成后可推送至SWR供沙箱使用。
 
#### 操作流程
整体流程分为三个步骤：
1. **编译ENVD二进制**：根据目标镜像的CPU架构编译Linux版本的ENVD。
2. **准备辅助文件**：健康检查脚本和启动脚本。
3. **编写Dockerfile并构建镜像**：将ENVD集成到业务镜像中，并推送至SWR。
 
#### 步骤一：编译ENVD二进制
1. 拉取ENVD代码。 
   ```
   git clone git@github.com:e2b-dev/infra.git
   ```
   
   
2. 进入envd目录，根据目标镜像的CPU架构构建二进制。 
   ```
   cd packages/envd
   CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o envd main.go
   ```
   如果需要构建ARM64架构的镜像，请将其中的*GOARCH=amd64* 改为*GOARCH=arm64*。
   
   
3. 验证编译结果。执行目录下应生成envd二进制文件。 
   ```
   ls -la envd
   ```
   
   
 
#### 步骤二：准备辅助文件
您需要准备两个辅助文件：健康检查脚本和启动脚本。
#### 健康检查脚本（envd-healthcheck.sh）
ENVD启动后需要一定时间完成初始化。健康检查脚本通过轮询ENVD的状态接口，确保ENVD完全就绪后再启动业务应用，避免后续操作因ENVD未就绪而失败。
1. 创建envd-healthcheck.sh文件。 
   ```
   vi envd-healthcheck.sh
   ```
   
   
2. 按"i"进入编辑模式，输入以下脚本内容。 
   ```
   #!/bin/bash
   # Custom health check for ENVD Server
   # Verifies the server is responsive via the /api/status endpoint
   MAX_RETRIES=50
   RETRY_INTERVAL=0.2
   for i in $(seq 1 $MAX_RETRIES); do
       status_code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:49983/health")
       if [ "$status_code" -eq 204 ]; then
           echo "ENVD Server is healthy"
           exit 0
       fi
       if [ $((i % 10)) -eq 0 ]; then
           echo "Waiting for ENVD Server to become healthy... (attempt $i/$MAX_RETRIES)"
       fi
       sleep $RETRY_INTERVAL
   done
   echo "ENVD Server health check failed after $MAX_RETRIES attempts"
   exit 1
   ```
   
   
3. 修改完成后，按"Esc"，输入:wq保存并退出文件编辑。
 
#### 启动脚本（entrypoint.sh）
容器启动时，需要先启动ENVD并等待其就绪，再执行原有业务启动逻辑。在业务镜像原有的entrypoint基础上，添加ENVD的启动和健康检查逻辑。
1. 修改entrypoint.sh文件。 
   ```
   vi entrypoint.sh
   ```
   
   
2. 按"i"进入编辑模式，添加以下脚本内容。 
   ```
   function start_envd() {
   /path/to/envd -isnotfc -port 49983 -verbose &
   /path/to/envd-healthcheck.sh
   if [ $? -ne 0 ]; then
   echo "ENVD Server failed to start, aborting."
   exit 1
   fi
   }
   echo "Starting ENVD server..."
   start_envd
   # 原有的启动脚本内容，忽略。
   ```
   请注意替换*/path/to/envd* 和*/path/to/envd-healthcheck.sh*为容器中实际路径。
   
   
3. 修改完成后，按"Esc"，输入:wq保存并退出文件编辑。
 
#### 步骤三：构建镜像
#### Dockerfile编写
以下Dockerfile以业务镜像为基础，集成ENVD及其辅助文件：
1. 创建Dockerfile。 
   ```
   vi Dockerfile
   ```
   
   
2. 按"i"进入编辑模式，填写以下内容。 
   ```
   # 将用户镜像用作Base镜像
   FROM <user-image>
   # ENVD需要以root身份运行
   USER root
   # 安装tini作为PID 1进程
   RUN apt-get update \
       && apt-get install -y --no-install-recommends \
           tini \
       && rm -rf /var/lib/apt/lists/*
   # 复制ENVD二进制、健康检查脚本和启动脚本
   COPY local/path/to/envd /image/path/to/envd
   COPY local/path/to/envd-healthcheck.sh /image/path/to/envd-healthcheck.sh
   COPY local/path/to/entrypoint.sh /image/path/to/entrypoint.sh
   RUN chmod +x /image/path/to/envd
   RUN chmod +x /image/path/to/envd-healthcheck.sh
   RUN chmod +x /image/path/to/entrypoint.sh
   # ENVD服务的监听端口
   EXPOSE 49983
   # 使用tini管理进程，-g 会将停止信号转发给所有子进程
   ENTRYPOINT ["/usr/bin/tini", "-g", "--", "/image/path/to/entrypoint.sh"]
   ```
   
   
3. 修改完成后，按"Esc"，输入:wq保存并退出文件编辑。
 
**其他补充场景示例**
#### 按需添加运行依赖
您可以在Dockerfile中按需添加其它依赖和配置。例如，如果需要通过ENVD执行Python脚本，镜像中必须包含Python运行环境，则可以在Dockerfile的安装命令部分插入以下内容：
```
RUN apt-get update \
    && apt-get install -y --no-install-recommends python3 \
    && rm -rf /var/lib/apt/lists/*
```
![](https://support.huaweicloud.com/usermanual-agentsphere/public_sys-resources/note_3.0-zh-cn.png)
仅当需要安装第三方Python包时才需额外安装python3-pip。
#### 非root镜像用户
如果用户镜像使用非root用户运行，需要进行额外适配，ENVD必须以root权限运行，但业务应用仍应以原镜像用户身份运行，遵循最小权限原则。
因此需要在Dockerfile中临时切换到root用户完成安装和授权，再切换回原有用户；在entrypoint.sh中则通过sudo仅提升ENVD进程的权限。
假设原镜像使用appuser用户运行，可以按以下方式进行配置。
1. 在Dockerfile中安装sudo，并仅允许appuser免密执行指定的ENVD启动命令： 
   ```
   FROM <user-image>
   USER root
   # 安装tini和sudo
   RUN apt-get update \
       && apt-get install -y --no-install-recommends \
           sudo \
           tini \
       && rm -rf /var/lib/apt/lists/*
   # 复制文件并设置权限
   COPY --chmod=0755 local/path/to/envd /image/path/to/envd
   COPY --chmod=0755 local/path/to/envd-healthcheck.sh /image/path/to/envd-healthcheck.sh
   COPY --chmod=0755 local/path/to/entrypoint.sh /image/path/to/entrypoint.sh
   # 配置sudoers：仅允许appuser免密执行ENVD启动命令
   RUN mkdir -p /etc/sudoers.d
   RUN echo 'appuser ALL=(root) NOPASSWD:SETENV /image/path/to/envd -isnotfc -port 49983 -verbose' \
           > /etc/sudoers.d/envd \
       && chmod 0440 /etc/sudoers.d/envd
   # 切回原镜像用户，原有应用仍以appuser身份运行
   USER appuser
   EXPOSE 49983
   ENTRYPOINT ["/usr/bin/tini", "-g", "--", "/image/path/to/entrypoint.sh"]
   ```
   ![](https://support.huaweicloud.com/usermanual-agentsphere/public_sys-resources/caution_3.0-zh-cn.png)
   请不要配置*appuser ALL=(ALL) NOPASSWD:ALL* ，仅授予启动ENVD所需的最小权限。如果修改了ENVD路径或启动参数，需同步更新*/etc/sudoers.d/envd*中的命令。
   
   
2. 修改entrypoint.sh中启动ENVD的命令，使用*sudo -n* 提权启动ENVD，*-n* 参数确保无法免密执行时立即失败，避免启动过程阻塞等待密码输入。
   
   ```
   function start_envd() {
           sudo -n -E /image/path/to/envd -isnotfc -port 49983 -verbose &
           /image/path/to/envd-healthcheck.sh
           if [ $? -ne 0 ]; then
                   echo "ENVD Server failed to start, aborting."
                   exit 1
           fi
   }
   echo "Starting ENVD server..."
   start_envd
   # 原有的启动脚本内容保持不变
   ```
   entrypoint.sh和原有应用仍以appuser身份运行，只有ENVD进程以root身份运行。
   
   
 
#### 构建并验证镜像
构建镜像命令如下：
```
docker build -t my-sandbox-image:latest .
```
其中，*my-sandbox-image:latest*为镜像名称和版本名称。
建议在推送前本地运行验证：
```
docker run --rm -p 49983:49983 my-sandbox-image:latest
```
验证要点：
- 启动日志中出现"ENVD Server is healthy"。
- 原有业务应用正常启动。
 
#### 推送镜像到SWR
构建并验证通过后，可将镜像推送到华为云容器镜像服务（SWR），供沙箱模板使用。
以基础版SWR为例，步骤如下：
1. 登录[SWR控制台](https://console.huaweicloud.com/swr/#/swr/dashboard)，选择左侧导航栏的"组织管理"，单击页面右上角的"创建组织"，创建一个组织。
   
   如已有组织可跳过此步骤。
   
   
2. 在左侧导航栏选择"我的镜像"，单击右侧"客户端上传"，在弹出的页面中单击"生成登录指令"，单击![](https://support.huaweicloud.com/usermanual-agentsphere/zh-cn_image_0000002701413295.png)复制临时登录指令。
3. 在集群节点上执行上一步复制的登录指令，登录成功会显示"Login Succeeded"。
4. 给镜像打上SWR标签 
   ```
   docker tag my-sandbox-image:latest swr.cn-north-4.myhuaweicloud.com/<namespace>/my-sandbox-image:latest
   ```
   其中，*swr.cn-north-4.myhuaweicloud.com* 为镜像仓库地址可在SWR控制台上查询，[登录指令]中末尾的域名即为镜像仓库地址；*\<namespace\>*为SWR中已创建的组织名称。
   
   
5. 推送镜像到 SWR： 
   ```
   docker push swr.cn-north-4.myhuaweicloud.com/<namespace>/my-sandbox-image:latest
   ```
   推送完成后，可在SWR控制台对应组织的镜像列表中查看到该镜像。
   
   
 
#### 相关文档
在创建沙箱模板时，即可选择已上传的SWR镜像，详情请参见[创建沙箱模板](https://support.huaweicloud.com/usermanual-agentsphere/agentsphere_03_0006.html)。
