Skip to content

feat: 🎸 support docker all-in-one image #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Build the frontend
FROM node:18-alpine AS frontend-builder

WORKDIR /app

COPY frontend/package.json frontend/package-lock.json ./

RUN apk add --no-cache libc6-compat
RUN npm config delete proxy
RUN npm ci

COPY frontend/. .
COPY frontend/.env.sample .env.production

ENV NODE_ENV=production

RUN npm run build

# Build the backend
FROM golang AS backend-builder

ARG TARGETARCH

WORKDIR /app
COPY . .

RUN GOARCH=${TARGETARCH} make bin/gcopy

# Final stage: Combined container
FROM node:18-alpine

LABEL maintainer="llaoj <[email protected]>"

WORKDIR /app

ENV NODE_ENV=production
ENV PORT=3375
ENV HOSTNAME=0.0.0.0

# Install nginx
RUN apk add --no-cache nginx

# Copy backend binary
COPY --from=backend-builder /app/bin/gcopy /usr/local/bin/gcopy

# Copy frontend build
COPY --from=frontend-builder /app/public ./public
COPY --from=frontend-builder /app/.next/standalone ./
COPY --from=frontend-builder /app/.next/static ./.next/static

# Expose port
EXPOSE 80

# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

COPY --chmod=755 entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

CMD [""]
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ PKG:=github.com/llaoj/gcopy
GCOPY_IMAGE_REPO:=$(REGISTRY)/gcopy
# The image repo of the gcopy web client container image.
GCOPY_FRONTEND_IMAGE_REPO:=$(REGISTRY)/gcopy-frontend
# The image repo of the gcopy all-in-one container image.
GCOPY_ALL_IMAGE_REPO:=$(REGISTRY)/gcopy-all

# Disable cgo by default to make the binary statically linked.
CGO_ENABLED:=0
Expand Down Expand Up @@ -51,6 +53,7 @@ push-container: clean
docker buildx create --platform $(DOCKER_PLATFORMS) --use
docker buildx build --push --platform $(DOCKER_PLATFORMS) -t $(GCOPY_IMAGE_REPO):$(TAG) -t $(GCOPY_IMAGE_REPO):latest -f build/gcopy/Dockerfile .
docker buildx build --push --platform $(DOCKER_PLATFORMS) -t $(GCOPY_FRONTEND_IMAGE_REPO):$(TAG) -t $(GCOPY_FRONTEND_IMAGE_REPO):latest -f build/frontend/Dockerfile .
docker buildx build --push --platform $(DOCKER_PLATFORMS) -t $(GCOPY_ALL_IMAGE_REPO):$(TAG) -t $(GCOPY_ALL_IMAGE_REPO):latest -f Dockerfile .

clean:
rm -rf bin/
Expand Down
21 changes: 21 additions & 0 deletions deploy/docker-compose-all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
gcopy:
image: llaoj/gcopy-all:latest # 或者使用你的镜像名称
container_name: gcopy
restart: unless-stopped
ports:
- "3375:3375" # 前端端口
- "3376:3376" # 后端端口
environment:
- APP_KEY=your_app_key_here # 必需
- SMTP_HOST=smtp.example.com # 必需
- [email protected] # 必需
- SMTP_PASSWORD=your_smtp_password # 必需
# 可选配置,使用默认值
- SMTP_PORT=587
- SMTP_SSL=true
- SMTP_SENDER=${SMTP_USERNAME}
- MAX_CONTENT_LENGTH=10

volumes:
gcopy_data:
37 changes: 37 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

set -eu

# Validate required environment variables
if [ -z "${APP_KEY:-}" ] || [ -z "${SMTP_HOST:-}" ] || [ -z "${SMTP_USERNAME:-}" ] || [ -z "${SMTP_PASSWORD:-}" ]; then
echo "Error: Required environment variables are not set"
echo "Required: APP_KEY, SMTP_HOST, SMTP_USERNAME, SMTP_PASSWORD"
exit 1
fi

# Start nginx
nginx -g 'daemon off;' &

# Start gcopy backend with default values where appropriate
/usr/local/bin/gcopy \
--app-key="${APP_KEY}" \
--smtp-host="${SMTP_HOST}" \
--smtp-port="${SMTP_PORT:-587}" \
--smtp-username="${SMTP_USERNAME}" \
--smtp-password="${SMTP_PASSWORD}" \
--smtp-ssl="${SMTP_SSL:-true}" \
--smtp-sender="${SMTP_SENDER:-${SMTP_USERNAME}}" \
--max-content-length="${MAX_CONTENT_LENGTH:-10}" &

# Wait for backend to be ready
sleep 2

# Start frontend
cd /app && NODE_ENV=production PORT=3375 exec node server.js &

# Wait for any process to exit
wait -n

# Exit with status of process that exited first
exit $?

2 changes: 1 addition & 1 deletion frontend/.env.sample
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SERVER_URL=http://gcopy:3376
SERVER_URL=http://127.0.0.1:3376
86 changes: 86 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
user nginx;
worker_processes auto;
error_log stderr warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /dev/stdout main;

# 文件传输优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;

# 超时设置
keepalive_timeout 65;
client_max_body_size 100m;
client_body_timeout 300s;
client_header_timeout 60s;
send_timeout 300s;
proxy_read_timeout 300s;
proxy_connect_timeout 60s;
proxy_send_timeout 300s;

# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

upstream frontend {
server 127.0.0.1:3375;
keepalive 32;
}

upstream backend {
server 127.0.0.1:3376;
keepalive 32;
}

server {
listen 80;
server_name localhost;

# 安全相关头部
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";

# API 路由
location /api/v1/ {
proxy_pass http://backend/api/v1/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_max_temp_file_size 0;
}

# 前端路由
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}