重构 Dockerfile 添加构建过程
This commit is contained in:
42
Dockerfile
42
Dockerfile
@@ -1,10 +1,44 @@
|
||||
FROM ubuntu:20.04
|
||||
# 第一阶段:构建
|
||||
FROM golang:1.24.0 AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# 复制Go模块文件
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 编译
|
||||
RUN GOOS=linux GOARCH=amd64 go build -ldflags '-w -s' -o bin/platform_linux_amd64 cmd/main/main.go
|
||||
|
||||
# 第二阶段:运行环境
|
||||
FROM ubuntu:24.04
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./bin/platform_linux_amd64 /app/platform
|
||||
# 安装依赖包
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 从构建阶段复制编译好的二进制文件
|
||||
COPY --from=builder /build/bin/platform_linux_amd64 /app/platform
|
||||
|
||||
# 设置可执行权限
|
||||
RUN chmod +x /app/platform
|
||||
|
||||
EXPOSE $APP_PORT
|
||||
# 创建存放密钥文件的目录
|
||||
RUN mkdir -p /app/certs
|
||||
|
||||
CMD ["/app/proxy"]
|
||||
# 声明暴露端口(实际端口通过环境变量传入)
|
||||
ENV APP_PORT=8080
|
||||
EXPOSE ${APP_PORT}
|
||||
|
||||
# 声明卷,用于在运行时挂载私密的证书文件
|
||||
VOLUME ["/app/certs"]
|
||||
|
||||
# 启动平台服务
|
||||
CMD ["/app/platform"]
|
||||
36
build.ps1
36
build.ps1
@@ -1,36 +0,0 @@
|
||||
Remove-Job *
|
||||
|
||||
$tasks = 0
|
||||
$start = Get-Date
|
||||
|
||||
$tasks++
|
||||
Write-Output "building platform for linux amd64..."
|
||||
Start-Job -ScriptBlock {
|
||||
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -ldflags '-w -s' -o bin/platform_linux_amd64 cmd/main/main.go
|
||||
} | Out-Null
|
||||
|
||||
$tasks++
|
||||
Write-Output "building tasks for linux amd64..."
|
||||
Start-Job -ScriptBlock {
|
||||
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -ldflags '-w -s' -o bin/tasks_linux_amd64 cmd/tasks/main.go
|
||||
} | Out-Null
|
||||
|
||||
# Wait for all jobs to complete
|
||||
while ($tasks -gt 0)
|
||||
{
|
||||
foreach ($job in Get-Job)
|
||||
{
|
||||
if ($job.State -eq "Completed")
|
||||
{
|
||||
$tasks--
|
||||
$job | Receive-Job
|
||||
$job | Remove-Job
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$end = Get-Date
|
||||
|
||||
Write-Output "build completed"
|
||||
Write-Output "time taken: $( ($end - $start).TotalSeconds ) seconds"
|
||||
Write-Output "output files are in ./bin/"
|
||||
@@ -1,132 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"platform/pkg/env"
|
||||
"platform/pkg/logs"
|
||||
"platform/pkg/rds"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var RemoveEndpoint = "http://localhost:8080/api/channel/remove"
|
||||
|
||||
func main() {
|
||||
Start()
|
||||
}
|
||||
|
||||
var taskList = make(map[string]func(ctx context.Context, curr time.Time) error)
|
||||
|
||||
func Start() {
|
||||
ctx := context.Background()
|
||||
|
||||
env.Init()
|
||||
logs.Init()
|
||||
rds.Init()
|
||||
|
||||
taskList["stopChannels"] = stopChannels
|
||||
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
// 互斥锁确保同一时间只有一个协程运行
|
||||
// 如果之前的 tick 操作未完成,则跳过当前 tick
|
||||
var mutex = &sync.Mutex{}
|
||||
for curr := range ticker.C {
|
||||
if mutex.TryLock() {
|
||||
err := process(ctx, curr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mutex.Unlock()
|
||||
} else {
|
||||
slog.Warn("skip tick", slog.String("tick", curr.Format("2006-01-02 15:04:05")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func process(ctx context.Context, curr time.Time) error {
|
||||
|
||||
// todo 异步化
|
||||
for name, task := range taskList {
|
||||
err := task(ctx, curr)
|
||||
if err != nil {
|
||||
slog.Error("task failed", slog.String("task", name), slog.String("error", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopChannels(ctx context.Context, curr time.Time) error {
|
||||
|
||||
// 查询过期的 channel
|
||||
result, err := rds.Client.ZRangeByScore(ctx, "tasks:channel", &redis.ZRangeBy{
|
||||
Min: "0",
|
||||
Max: strconv.FormatInt(curr.Unix(), 10),
|
||||
}).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ids := make([]int32, len(result))
|
||||
for i, str := range result {
|
||||
id, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ids[i] = int32(id)
|
||||
}
|
||||
slog.Debug("stopChannels", slog.String("result", strings.Join(result, ",")))
|
||||
|
||||
// 删除过期的 channel
|
||||
body, err := json.Marshal(map[string]any{
|
||||
"by_ids": ids,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest(
|
||||
http.MethodPost,
|
||||
RemoveEndpoint,
|
||||
strings.NewReader(string(body)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.SetBasicAuth("tasks", "tasks")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(Body io.ReadCloser) {
|
||||
_ = Body.Close()
|
||||
}(resp.Body)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New("failed to stop channels: " + string(body))
|
||||
}
|
||||
|
||||
// 删除 redis 中的 channel
|
||||
_, err = rds.Client.ZRemRangeByScore(ctx, "tasks:channel", "0", strconv.FormatInt(curr.Unix(), 10)).Result()
|
||||
|
||||
return nil
|
||||
}
|
||||
90
docs/docker-deployment.md
Normal file
90
docs/docker-deployment.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Docker 部署说明
|
||||
|
||||
本文档说明如何使用 Docker 构建和部署平台服务。
|
||||
|
||||
## 构建镜像
|
||||
|
||||
在项目根目录下执行以下命令构建 Docker 镜像:
|
||||
|
||||
```bash
|
||||
docker build -t platform:latest .
|
||||
```
|
||||
|
||||
## 生产环境部署
|
||||
|
||||
由于涉及敏感的 `.pem` 证书文件,这些文件不包含在代码库或 Docker 镜像中,而是在运行时通过卷挂载的方式提供。
|
||||
|
||||
### 准备证书文件
|
||||
|
||||
1. 在生产服务器上创建一个目录用于存放证书文件,例如:`/path/to/certs/`
|
||||
2. 将必要的证书文件放入此目录:
|
||||
- `pub_key.pem`
|
||||
- `apiclient_key.pem`
|
||||
|
||||
### 运行容器
|
||||
|
||||
使用以下命令运行容器,挂载证书目录:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name platform \
|
||||
-p 8080:8080 \
|
||||
-e APP_PORT=8080 \
|
||||
-v /path/to/certs:/app/certs \
|
||||
platform:latest
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
可以通过环境变量来配置应用程序:
|
||||
|
||||
- `APP_PORT`: 应用监听的端口号(默认: 8080)
|
||||
- 其他应用相关的环境变量可以通过 `-e` 参数添加
|
||||
|
||||
### 证书路径配置
|
||||
|
||||
如果应用程序需要知道证书的路径,可以通过环境变量配置:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name platform \
|
||||
-p 8080:8080 \
|
||||
-e APP_PORT=8080 \
|
||||
-e PUB_KEY_PATH=/app/certs/pub_key.pem \
|
||||
-e APICLIENT_KEY_PATH=/app/certs/apiclient_key.pem \
|
||||
-v /path/to/certs:/app/certs \
|
||||
platform:latest
|
||||
```
|
||||
|
||||
## 使用 Docker Compose
|
||||
|
||||
也可以通过 Docker Compose 进行部署,创建 `docker-compose.yml` 文件:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
platform:
|
||||
image: platform:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- APP_PORT=8080
|
||||
- PUB_KEY_PATH=/app/certs/pub_key.pem
|
||||
- APICLIENT_KEY_PATH=/app/certs/apiclient_key.pem
|
||||
volumes:
|
||||
- /path/to/certs:/app/certs
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
然后执行:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 安全建议
|
||||
|
||||
1. 确保证书文件的权限设置正确,仅允许必要的用户访问
|
||||
2. 在生产环境中考虑使用 Docker Secrets 或 Kubernetes Secrets 来管理敏感信息
|
||||
3. 定期更新证书和密钥
|
||||
8
go.mod
8
go.mod
@@ -3,8 +3,8 @@ module platform
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1
|
||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.6
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v4 v4.1.3
|
||||
github.com/alicebob/miniredis/v2 v2.34.0
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/gofiber/fiber/v2 v2.52.6
|
||||
@@ -27,15 +27,11 @@ require (
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 // indirect
|
||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v4 v4.1.3 // indirect
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
|
||||
github.com/alibabacloud-go/tea v1.3.8 // indirect
|
||||
github.com/alibabacloud-go/tea-utils v1.4.3 // indirect
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
|
||||
github.com/aliyun/credentials-go v1.4.5 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
|
||||
13
go.sum
13
go.sum
@@ -15,15 +15,11 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC
|
||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||
@@ -32,11 +28,8 @@ github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA
|
||||
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v4 v4.1.3 h1:32N2pGk28weVZ5/rjNk9gPx/jrRkR0rX9i8Id6IlyUY=
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v4 v4.1.3/go.mod h1:gPbHx4BTxLIDNRfYNGGmp6aIpeNBamtdDlPcK4UTUto=
|
||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.6 h1:XPck0S+7I8se2e8YnjA/D9OE6FzXwWo2UjlSziJs+z0=
|
||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.6/go.mod h1:Ia7UzBNwNCeNR3TxGQAWi6yNttIFWGiR4HzIlA3Dasc=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||
github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28=
|
||||
github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw=
|
||||
@@ -45,20 +38,15 @@ github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeG
|
||||
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||
github.com/alibabacloud-go/tea v1.3.8 h1:Sk2+BDJC//xJ1/Eljf+Dlg2u2tgWpA9P7mlb87AEcEs=
|
||||
github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.3 h1:8SzwmmRrOnQ09Hf5a9GyfJc0d7Sjv6fmsZoF4UDbFjo=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
|
||||
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
@@ -67,7 +55,6 @@ github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqR
|
||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||
github.com/aliyun/credentials-go v1.4.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk=
|
||||
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
|
||||
Reference in New Issue
Block a user