From f179800d0663e4479c8753cbeb9651e98b65407e Mon Sep 17 00:00:00 2001 From: bjarneo Date: Sat, 16 Nov 2024 17:57:06 +0100 Subject: [PATCH] feat: add network, volumes, cpus, memory --- README.md | 15 ++++++++++ main.go | 87 +++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c103b61..ab20828 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,10 @@ go build -o copepod | --dockerfile | | Dockerfile | Dockerfile path | | --build-arg | BUILD_ARGS | | Build arguments (KEY=VALUE) | | --rollback | | | Rollback to the previous instance | +| --network | DOCKER_NETWORK | | Docker network to connect to | +| --volume | | | Volume mount (host:container) | +| --cpus | DOCKER_CPUS | | Number of CPUs | +| --memory | DOCKER_MEMORY | | Memory limit | ### Example Commands @@ -125,6 +129,17 @@ Using build arguments: ./copepod --host example.com --user deploy --build-arg GIT_HASH=$(git rev-parse HEAD) ``` +Advanced deployment with resource limits and volumes: + +```bash +./copepod --host example.com --user deploy \ + --network my-network \ + --volume /host/data:/container/data \ + --volume /host/config:/container/config \ + --cpus 2 \ + --memory 1g +``` + ## Directory Structure Your project directory should look like this: diff --git a/main.go b/main.go index 68c101f..c427c63 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,10 @@ type Config struct { EnvFile string `json:"envFile"` Rollback bool `json:"rollback"` BuildArgs map[string]string `json:"buildArgs"` + Network string `json:"network"` + Volumes []string `json:"volumes"` + CPUs string `json:"cpus"` + Memory string `json:"memory"` } // Logger handles logging to both console and file @@ -60,36 +64,47 @@ Usage: Options: --host Remote host to deploy to --user SSH user for remote host - --image Docker image name (default: copepod_app) + --image Docker image name (default: app) --dockerfile Path to the dockerfile (default: Dockerfile) --tag Docker image tag (default: latest) --platform Docker platform (default: linux/amd64) --ssh-key Path to SSH key (default: "") - --container-name Name for the container (default: copepod_app) + --container-name Name for the container (default: app) --container-port Container port (default: 3000) --host-port Host port (default: 3000) --env-file Environment file (default: "") --build-arg Build arguments (can be specified multiple times, format: KEY=VALUE) + --network Docker network to connect to + --volume Volume mount (can be specified multiple times, format: host:container) + --cpus Number of CPUs (e.g., '0.5' or '2') + --memory Memory limit (e.g., '512m' or '2g') --rollback Rollback to the previous version + --version Show version information --help Show this help message Environment Variables: - HOST Remote host to deploy to - HOST_USER SSH user for remote host - DOCKER_IMAGE_NAME Docker image name - DOCKER_IMAGE_TAG Docker image tag - HOST_PLATFORM Docker platform - SSH_KEY_PATH Path to SSH key - DOCKER_CONTAINER_NAME Name for the container - DOCKER_CONTAINER_PORT Container port - HOST_PORT Host port - DOCKER_CONTAINER_ENV_FILE Environment file - BUILD_ARGS Build arguments (comma-separated KEY=VALUE pairs) + HOST Remote host to deploy to + HOST_USER SSH user for remote host + HOST_PORT Host port + HOST_PLATFORM Docker platform + SSH_KEY_PATH Path to SSH key + DOCKER_IMAGE_NAME Docker image name + DOCKER_IMAGE_TAG Docker image tag + DOCKER_CONTAINER_NAME Name for the container + DOCKER_CONTAINER_PORT Container port + DOCKER_BUILD_ARGS Build arguments (comma-separated KEY=VALUE pairs) + DOCKER_CONTAINER_ENV_FILE Environment file + DOCKER_NETWORK Docker network to connect to + DOCKER_CPUS Number of CPUs + DOCKER_MEMORY Memory limit + Examples: copepod --host example.com --user deploy copepod --host example.com --user deploy --build-arg VERSION=1.0.0 --build-arg ENV=prod copepod --env-file .env.production --build-arg GIT_HASH=$(git rev-parse HEAD) + copepod --host example.com --user deploy --cpus "0.5" --memory "512m" + copepod --rollback # Rollback to the previous version ` // NewLogger creates a new logger instance @@ -149,6 +164,7 @@ func LoadConfig() Config { var showHelp bool var showVersion bool var buildArgs arrayFlags + var volumeFlags arrayFlags // Initialize BuildArgs map config.BuildArgs = make(map[string]string) @@ -166,6 +182,10 @@ func LoadConfig() Config { flag.StringVar(&config.HostPort, "host-port", getEnv("HOST_PORT", "3000"), "Host port") flag.StringVar(&config.EnvFile, "env-file", getEnv("DOCKER_CONTAINER_ENV_FILE", ""), "Environment file") flag.Var(&buildArgs, "build-arg", "Build argument in KEY=VALUE format (can be specified multiple times)") + flag.Var(&volumeFlags, "volume", "Volume mount in format 'host:container' (can be specified multiple times)") + flag.StringVar(&config.Network, "network", getEnv("DOCKER_NETWORK", ""), "Docker network to connect to") + flag.StringVar(&config.CPUs, "cpus", getEnv("DOCKER_CPUS", ""), "Number of CPUs (e.g., '0.5' or '2')") + flag.StringVar(&config.Memory, "memory", getEnv("DOCKER_MEMORY", ""), "Memory limit (e.g., '512m' or '2g')") flag.BoolVar(&showHelp, "help", false, "Show help message") flag.BoolVar(&config.Rollback, "rollback", false, "Rollback to previous version") flag.BoolVar(&showVersion, "version", false, "Show version information") @@ -198,7 +218,7 @@ func LoadConfig() Config { } // Process build arguments from environment variable - if envBuildArgs := os.Getenv("BUILD_ARGS"); envBuildArgs != "" { + if envBuildArgs := os.Getenv("DOCKER_BUILD_ARGS"); envBuildArgs != "" { for _, arg := range strings.Split(envBuildArgs, ",") { parts := strings.SplitN(arg, "=", 2) if len(parts) == 2 { @@ -215,6 +235,9 @@ func LoadConfig() Config { } } + // Assign volume flags to config + config.Volumes = []string(volumeFlags) + return config } @@ -521,18 +544,40 @@ func Deploy(config *Config, logger *Logger) error { } } - // Prepare remote commands - envFileFlag := "" - if _, err := os.Stat(config.EnvFile); err == nil { - envFileFlag = fmt.Sprintf("--env-file ~/%s", config.EnvFile) + // Prepare container configuration + containerConfig := []string{ + "-d", + "--name", config.ContainerName, + "--restart", "unless-stopped", + "-p", fmt.Sprintf("%s:%s", config.HostPort, config.ContainerPort), + } + + if config.Network != "" { + containerConfig = append(containerConfig, "--network", config.Network) + } + + if config.CPUs != "" { + containerConfig = append(containerConfig, "--cpus", config.CPUs) } + if config.Memory != "" { + containerConfig = append(containerConfig, "--memory", config.Memory) + } + + for _, volume := range config.Volumes { + containerConfig = append(containerConfig, "-v", volume) + } + + if config.EnvFile != "" { + containerConfig = append(containerConfig, fmt.Sprintf("--env-file ~/%s", config.EnvFile)) + } + + containerConfig = append(containerConfig, fmt.Sprintf("%s:%s", config.Image, config.Tag)) + remoteCommands := strings.Join([]string{ fmt.Sprintf("docker stop %s || true", config.ContainerName), fmt.Sprintf("docker rm %s || true", config.ContainerName), - fmt.Sprintf("docker run -d --name %s --restart unless-stopped -p %s:%s %s %s:%s", - config.ContainerName, config.HostPort, config.ContainerPort, - envFileFlag, config.Image, config.Tag), + fmt.Sprintf("docker run %s", strings.Join(containerConfig, " ")), }, " && ") // Execute remote commands