tsk-8: Added docker support (#13)
Closes #8 Reviewed-on: phoenix/textsender-auth#13 Co-authored-by: phoenix <kundeng00@pm.me> Co-committed-by: phoenix <kundeng00@pm.me>
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
vendor/
|
||||||
|
|
||||||
|
# Ignore git directory
|
||||||
|
.git/
|
||||||
|
|
||||||
|
.gitea/
|
||||||
|
|
||||||
|
# Ignore environment files (configure via docker-compose instead)
|
||||||
|
.env*
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
SECRET_KEY=NULqYIzgt28bTiyziCd7IOO7b6LnWDW!
|
||||||
|
DB_NAME=textsender_auth_db
|
||||||
|
DB_USER=textsender_auth
|
||||||
|
DB_PASSWORD=password
|
||||||
|
DB_HOST=auth_db
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_SSLMODE=disable
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
|
.env.docker
|
||||||
|
|
||||||
/vendor
|
/vendor
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
# Multi-stage Dockerfile for Go application
|
||||||
|
FROM golang:1.25.3 AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
openssh-client git
|
||||||
|
|
||||||
|
RUN mkdir -p -m 0700 ~/.ssh && \
|
||||||
|
ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
# Configure Git to use SSH for GitHub
|
||||||
|
RUN git config --global url."ssh://git@git.kundeng.us".insteadOf "https://git.kundeng.us"
|
||||||
|
|
||||||
|
# Set up the Go environment for private modules
|
||||||
|
ENV GOPRIVATE=git.kundeng.us
|
||||||
|
|
||||||
|
|
||||||
|
# Copy go mod and sum files
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
|
||||||
|
RUN --mount=type=ssh mkdir src && \
|
||||||
|
go mod download
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY ./cmd ./cmd
|
||||||
|
COPY ./internal ./internal
|
||||||
|
COPY ./Makefile .
|
||||||
|
COPY ./.env .
|
||||||
|
COPY ./migrations ./migrations
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux make build
|
||||||
|
|
||||||
|
# Runtime stage
|
||||||
|
FROM alpine:latest AS production
|
||||||
|
|
||||||
|
RUN apk --no-cache add ca-certificates
|
||||||
|
|
||||||
|
WORKDIR /root/
|
||||||
|
|
||||||
|
# Copy the pre-built binary file from the previous stage
|
||||||
|
COPY --from=builder /app/textsender-auth .
|
||||||
|
COPY --from=builder /app/.env ./
|
||||||
|
COPY --from=builder /app/migrations ./migrations
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 9080
|
||||||
|
|
||||||
|
# Command to run the executable
|
||||||
|
CMD ["./textsender-auth"]
|
||||||
+9
-2
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
|
||||||
"git.kundeng.us/phoenix/textsender-auth/internal/config"
|
"git.kundeng.us/phoenix/textsender-auth/internal/config"
|
||||||
"git.kundeng.us/phoenix/textsender-auth/internal/db"
|
database "git.kundeng.us/phoenix/textsender-auth/internal/db"
|
||||||
"git.kundeng.us/phoenix/textsender-auth/internal/handler"
|
"git.kundeng.us/phoenix/textsender-auth/internal/handler"
|
||||||
"git.kundeng.us/phoenix/textsender-auth/internal/handler/endpoint"
|
"git.kundeng.us/phoenix/textsender-auth/internal/handler/endpoint"
|
||||||
mdleware "git.kundeng.us/phoenix/textsender-auth/internal/middleware"
|
mdleware "git.kundeng.us/phoenix/textsender-auth/internal/middleware"
|
||||||
@@ -28,7 +28,7 @@ func main() {
|
|||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := db.NewDatabase(cfg.GetDBConnString())
|
db, err := database.NewDatabase(cfg.GetDBConnString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to connect to database: %v", err)
|
log.Fatalf("Failed to connect to database: %v", err)
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Println("Database reset completed. Exiting.")
|
log.Println("Database reset completed. Exiting.")
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
if exists, err := database.TableExists(ctx, db.Pool, "users"); err == nil && !exists {
|
||||||
|
fmt.Println("Resetting database")
|
||||||
|
err = db.ResetDatabase(ctx)
|
||||||
|
} else {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
version: '3.8' # Use a recent version
|
||||||
|
|
||||||
|
services:
|
||||||
|
auth_api:
|
||||||
|
build: # Tells docker-compose to build the Dockerfile in the current directory
|
||||||
|
context: .
|
||||||
|
ssh: ["default"] # Uses host's SSH agent
|
||||||
|
container_name: textsender_auth # Optional: Give the container a specific name
|
||||||
|
ports:
|
||||||
|
# Map host port 8000 to container port 3000 (adjust as needed)
|
||||||
|
- "9080:9080"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
auth_db:
|
||||||
|
condition: service_healthy # Wait for the DB to be healthy before starting the app
|
||||||
|
restart: unless-stopped # Optional: Restart policy
|
||||||
|
|
||||||
|
# PostgreSQL Database Service
|
||||||
|
auth_db:
|
||||||
|
image: postgres:18.0-alpine # Use an official Postgres image (Alpine variant is smaller)
|
||||||
|
container_name: textsender_auth_db # Optional: Give the container a specific name
|
||||||
|
environment:
|
||||||
|
# These MUST match the user, password, and database name in the DATABASE_URL above
|
||||||
|
POSTGRES_USER: ${POSTGRES_AUTH_USER:-textsender_auth}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_AUTH_PASSWORD:-password}
|
||||||
|
POSTGRES_DB: ${POSTGRES_AUTH_DB:-textsender_auth_db}
|
||||||
|
volumes:
|
||||||
|
# Persist database data using a named volume
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
ports: []
|
||||||
|
healthcheck:
|
||||||
|
# Checks if Postgres is ready to accept connections
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
restart: always # Optional: Restart policy
|
||||||
|
|
||||||
|
# Define the named volume for data persistence
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local # Use the default local driver
|
||||||
@@ -27,11 +27,9 @@ type ConnectionInfo struct {
|
|||||||
SslMode string
|
SslMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Port = "9080"
|
const Port = "9080"
|
||||||
const App_Name = "textsender_auth"
|
const App_Name = "textsender_auth"
|
||||||
|
|
||||||
|
|
||||||
func (ci ConnectionInfo) Parse() string {
|
func (ci ConnectionInfo) Parse() string {
|
||||||
return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", ci.Username, ci.Password, ci.Host, ci.Port, ci.Database, ci.SslMode)
|
return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", ci.Username, ci.Password, ci.Host, ci.Port, ci.Database, ci.SslMode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,25 @@ func NewDatabase(connString string) (*Database, error) {
|
|||||||
return &Database{Pool: pool}, nil
|
return &Database{Pool: pool}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TableExists(ctx context.Context, conn *pgxpool.Pool, tableName string) (bool, error) {
|
||||||
|
var exists bool
|
||||||
|
|
||||||
|
query := `
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = $1
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
err := conn.QueryRow(ctx, query, tableName).Scan(&exists)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error checking if table exists: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db *Database) Close() {
|
func (db *Database) Close() {
|
||||||
if db.Pool != nil {
|
if db.Pool != nil {
|
||||||
db.Pool.Close()
|
db.Pool.Close()
|
||||||
|
|||||||
Reference in New Issue
Block a user