
# 使用Go构建容器镜像开发事件函数
使用容器镜像创建并执行事件函数的完整操作步骤可参考[使用容器镜像创建并执行事件函数](https://support.huaweicloud.com/qs-functiongraph/functiongraph_04_0104.html)，本章节介绍如何使用Go语言制作镜像，并进行本地验证。
#### 步骤一：制作镜像
以在linux x86 64位系统上制作镜像为例（系统配置无要求）。
1. 执行以下命令，创建一个空文件夹。
   ```
   mkdir custom_container_event_example && cd custom_container_event_example
   ```
   
2. 以golang语言为例，实现一个Http Server，处理函数初始化init请求和函数调用invoke请求并响应。
   创建一个"server_demo.go"文件，引入gin依赖包，实现Method为POST和Path为/invoke的函数执行入口。通过init函数进行初始化配置，Golang会自动执行该函数。示例代码如下：
   ```
   package main
   import (
      "fmt"
      "net/http"
      "time"
      "github.com/gin-gonic/gin"  // 导入 Gin 框架
   )
   // 初始化函数，程序启动时会执行
   func init() {
      fmt.Println("init in main.go ")
   }
   // Logger 是一个中间件函数，用于记录请求和响应的信息
   func Logger() gin.HandlerFunc {
      return func(c *gin.Context) {
         start := time.Now()
         reqBody, _ := c.GetRawData()
         fmt.Printf("[INFO] Request: %s %s %s\n", c.Request.Method, c.Request.RequestURI, reqBody)
         c.Next()
         end := time.Now()
         latency := end.Sub(start)
         respBody := string(rune(c.Writer.Size()))
         fmt.Printf("[INFO] Response: %s %s %s (%v)\n", c.Request.Method, c.Request.RequestURI, respBody, latency)
      }
   }
   // invoke 是一个处理函数，处理 POST /invoke 路由的请求
   func invoke(c *gin.Context) {
      println("hello world")
      c.String(http.StatusOK, "*** hello world ***")
      return
   }
   func main() {
      router := gin.Default()  // 创建一个默认的 Gin 路由器
      router.Use(Logger())  // 使用 Logger 中间件
      router.POST("/invoke", invoke)  // 注册一个处理HTTP POST请求的路由，路径为/invoke，当客户端发送一个POST请求到/invoke路径时，Gin框架会调用invoke函数来处理这个请求。
      err := router.Run(":8000")  // 启动 HTTP 服务器，监听 8000 端口
      if err != nil {
         return
      }
   }
   ```
   
3. 执行以下命令进行编译，生成server_demo二进制文件。
   ```
   go build server_demo.go
   ```
   
4. 创建Dockerfile文件，使用编译后的文件名替换dockerfile中的server_demo。文件内容如下：
   ```
   FROM ubuntu:22.04
   ENV HOME=/home/paas
   ENV GROUP_ID=1003
   ENV GROUP_NAME=paas_user
   ENV USER_ID=1003
   ENV USER_NAME=paas_user
   RUN mkdir -m 550 ${HOME} && groupadd -g ${GROUP_ID} ${GROUP_NAME} && useradd -u ${USER_ID} -g ${GROUP_ID} ${USER_NAME}
   COPY server_demo ${HOME}
   RUN chown -R ${USER_ID}:${GROUP_ID} ${HOME}
   RUN chmod -R 775 ${HOME}
   USER ${USER_NAME}
   WORKDIR ${HOME}
   EXPOSE 8000
   ENTRYPOINT ["./server_demo"]
   ```
   表1参数说明 
   | 参数         | 说明                                                                                                                          |
   |:---|:---|
   | FROM       | 指定基础镜像为ubuntu:22.04，基础镜像必须设置，值可修改。                                                                                          |
   | ENV        | 设置环境变量，设置HOME环境变量为/home/custom_container，设置GROUP_NAME和USER_NAME为custom_container，**USER_ID和GROUP_ID为1003**，这些环境变量必须设置，值可修改。 |
   | RUN        | 执行命令，格式为RUN \<命令\>。例如RUN mkdir -m 550 ${HOME}表示构建容器时创建${USER_NAME}用户的${HOME}目录。                                             |
   | COPY       | 从构建上下文复制文件或目录到镜像中。将"server_demo.go"文件拷贝到容器的${USER_NAME}用户的${HOME}目录下。                                                       |
   | USER       | 切换${USER_NAME}用户。                                                                                                           |
   | WORKDIR    | 切换工作目录到${USER_NAME}用户的${HOME}目录下。                                                                                           |
   | EXPOSE     | 声明容器运行时监听的端口。暴露容器的8000端口，请勿修改。                                                                                              |
   | ENTRYPOINT | 设置容器启动时运行的命令，使用./server_demo命令启动容器。                                                                                         |
      
   
5. 执行以下命令构建镜像。
   ```
   docker build -t custom_container_event_example:latest .
   ```
   指定镜像的名称为custom_container_event_example，版本为latest，"."指定Dockerfile所在目录，镜像构建命令将该路径下所有的内容打包给容器引擎帮助构建镜像。
   
 
#### 步骤二：本地验证
1. 执行以下命令启动docker容器。
   ```
   docker run -u 1003:1003 -p 8000:8000 custom_container_event_example:latest
   ```
   
2. 打开一个新的命令行窗口，向开放的8000端口发送消息，访问模板代码中指定的/invoke路径。
   ```
   curl -XPOST -H 'Content-Type: application/json' -d '{"message":"HelloWorld"}' localhost:8000/invoke
   ```
   将按照模块代码返回以下内容：
   ```
   *** hello world ***
   ```
   
 
#### 步骤三：配置函数
在本地完成容器镜像构建后，即可登录华为云控制台进行控制台操作。
后续操作步骤请参考[使用容器镜像创建并执行事件函数](https://support.huaweicloud.com/qs-functiongraph/functiongraph_04_0104.html#section4)，从步骤三：上传镜像开始操作。
#### 相关文档
- 关于函数开发的更多说明，如函数支持的运行时、函数支持的触发事件、函数工程打包规范以及如何在函数中引入动态链接库，请参见[函数开发概述](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0100.html)。
- 关于Go函数开发的接口定义和SDK接口说明，请参见[Go函数开发概述](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0504.html)。
 
