diff --git a/.gitignore b/.gitignore index 01ed840..5ad40b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ dist .DS_Store *.log -*.pid \ No newline at end of file +*.pid +docker/anklet* \ No newline at end of file diff --git a/Makefile b/Makefile index 2561b05..f747274 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,13 @@ LATEST-GIT-SHA := $(shell git rev-parse HEAD) VERSION := $(shell cat VERSION) FLAGS := -X main.version=$(VERSION) -X main.commit=$(LATEST-GIT-SHA) BIN := anklet -ARCH := $(shell arch) +ARCH ?= $(shell arch) ifeq ($(ARCH), i386) ARCH = amd64 endif +ifeq ($(ARCH), x86_64) + ARCH = amd64 +endif OS_TYPE ?= $(shell uname -s | tr '[:upper:]' '[:lower:]') BIN_FULL ?= dist/$(BIN)_v$(VERSION)_$(OS_TYPE)_$(ARCH) export PATH := $(shell go env GOPATH)/bin:$(PATH) @@ -40,3 +43,9 @@ install: mkdir -p ~/bin cp -f dist/$(BIN)_v$(VERSION)_$(OS_TYPE)_$(ARCH) ~/bin/$(BIN) +go.build: + GOARCH=$(ARCH) go build $(RACE) -ldflags "-X main.version=$(VERSION)" -o docker/$(BIN)_$(OS_TYPE)_$(ARCH) + chmod +x docker/$(BIN)_$(OS_TYPE)_$(ARCH) + +build-linux: + GOOS=linux OS_TYPE=linux $(MAKE) go.build \ No newline at end of file diff --git a/VERSION b/VERSION index 8adc70f..c18d72b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.0 \ No newline at end of file +0.8.1 \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..9cf1fa6 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest +RUN apk update && apk add ca-certificates +ARG TARGETARCH +COPY ./anklet_linux_${TARGETARCH} /usr/local/bin/anklet +ENTRYPOINT ["/usr/local/bin/anklet", "--attach"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d91c240 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.1' +services: + anklet-metrics-aggregator: + # build: + # context: ./ + # dockerfile: Dockerfile + image: veertu/anklet:latest + container_name: anklet-metrics-aggregator + # volumes: + # - /Users/nathanpierce/.config/anklet:/root/.config/anklet/ + ports: + - "8081:8081" + environment: + # - LOG_LEVEL=dev + - ANKLET_METRICS_AGGREGATOR=true + - ANKLET_METRICS_PORT=8081 + # - ANKLET_METRICS_URLS=http://anklet1:8080/metrics,http://anklet2:8081/metrics + - ANKLET_METRICS_URLS=http://host.docker.internal:8080/metrics + - ANKLET_METRICS_SLEEP_INTERVAL=10 + - ANKLET_METRICS_DATABASE_ENABLED=true + - ANKLET_METRICS_DATABASE_URL=host.docker.internal + - ANKLET_METRICS_DATABASE_PORT=6379 + - ANKLET_METRICS_DATABASE_USER= + - ANKLET_METRICS_DATABASE_PASSWORD= + - ANKLET_METRICS_DATABASE_DATABASE=0 \ No newline at end of file diff --git a/generate-dockerhub-tags.bash b/generate-dockerhub-tags.bash new file mode 100755 index 0000000..0277585 --- /dev/null +++ b/generate-dockerhub-tags.bash @@ -0,0 +1,21 @@ +#!/bin/bash +set -exo pipefail +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +pushd "${SCRIPT_DIR}" +DOCKERFILE_PATH="${SCRIPT_DIR}/docker" +NAME="anklet" +cleanup() { + rm -f "${DOCKERFILE_PATH}/${NAME}"* +} +ARCH=amd64 make build-linux +ARCH=arm64 make build-linux +ls -alht "${DOCKERFILE_PATH}/" +trap cleanup EXIT +pushd "${DOCKERFILE_PATH}" +docker buildx create --name mybuilder --use || true +docker buildx install || true +# make sure docker login is handled +docker build --no-cache --platform linux/amd64,linux/arm64 \ + -t veertu/"${NAME}":latest -t veertu/"$NAME:v$(cat "${SCRIPT_DIR}"/VERSION)" \ + --push . +popd \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index ebcfea4..48801d8 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -65,23 +65,23 @@ type Service struct { Workflows Workflow `yaml:"workflows"` } -func LoadConfig(configPath string) (*Config, error) { +func LoadConfig(configPath string) (Config, error) { + config := Config{} file, err := os.Open(configPath) if err != nil { - return nil, err + return config, err } defer file.Close() decoder := yaml.NewDecoder(file) - var config Config err = decoder.Decode(&config) if err != nil { - return nil, err + return config, err } - return &config, nil + return config, nil } -func LoadInEnvs(config *Config) (*Config, error) { +func LoadInEnvs(config Config) (Config, error) { envAggregator := os.Getenv("ANKLET_METRICS_AGGREGATOR") if envAggregator != "" { config.Metrics.Aggregator = envAggregator == "true" @@ -91,17 +91,15 @@ func LoadInEnvs(config *Config) (*Config, error) { if envPort != "" { config.Metrics.Port = envPort } - envMetricsURLs := os.Getenv("ANKLET_METRICS_URLS") if envMetricsURLs != "" { config.Metrics.MetricsURLs = strings.Split(envMetricsURLs, ",") } - envSleepInterval := os.Getenv("ANKLET_METRICS_SLEEP_INTERVAL") if envSleepInterval != "" { value, err := strconv.Atoi(envSleepInterval) if err != nil { - return nil, err + return Config{}, err } config.Metrics.SleepInterval = value } @@ -130,7 +128,7 @@ func LoadInEnvs(config *Config) (*Config, error) { if envDBPort != "" { port, err := strconv.Atoi(envDBPort) if err != nil { - return nil, err + return Config{}, err } config.Metrics.Database.Port = port } @@ -139,7 +137,7 @@ func LoadInEnvs(config *Config) (*Config, error) { if envDBDatabase != "" { database, err := strconv.Atoi(envDBDatabase) if err != nil { - return nil, err + return Config{}, err } config.Metrics.Database.Database = database } diff --git a/main.go b/main.go index 7a7a307..e2549c5 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,7 @@ var ( signalFlag = flag.String("s", "", `Send signal to the daemon: drain — graceful shutdown, will wait until all jobs finish before exiting stop — best effort graceful shutdown, interrupting the job as soon as possible`) + attachFlag = flag.Bool("attach", false, "Attach to the anklet and don't background it (useful for containers)") stop = make(chan struct{}) done = make(chan struct{}) shutDownMessage = "anklet service shut down" @@ -80,8 +81,10 @@ func main() { // obtain config loadedConfig, err := config.LoadConfig(configPath) if err != nil { - panic(err) + logger.InfoContext(parentCtx, "unable to load config.yml", "error", err) + // panic(err) } + logger.InfoContext(parentCtx, "loaded config", slog.Any("config", loadedConfig)) loadedConfig, err = config.LoadInEnvs(loadedConfig) if err != nil { panic(err) @@ -95,9 +98,6 @@ func main() { } parentCtx = context.WithValue(parentCtx, config.ContextKey("suffix"), suffix) - logger.DebugContext(parentCtx, "loaded config", slog.Any("config", loadedConfig)) - parentCtx = context.WithValue(parentCtx, config.ContextKey("config"), loadedConfig) - if loadedConfig.Log.FileDir == "" { loadedConfig.Log.FileDir = "./" } @@ -108,6 +108,9 @@ func main() { loadedConfig.WorkDir = "./" } + logger.DebugContext(parentCtx, "loaded config", slog.Any("config", loadedConfig)) + parentCtx = context.WithValue(parentCtx, config.ContextKey("config"), &loadedConfig) + daemonContext := &daemon.Context{ PidFileName: loadedConfig.PidFileDir + "anklet" + suffix + ".pid", PidFilePerm: 0644, @@ -157,16 +160,18 @@ func main() { } } - d, err := daemonContext.Reborn() - if err != nil { - log.Fatalln(err) - } - if d != nil { - return + if !*attachFlag { + d, err := daemonContext.Reborn() + if err != nil { + log.Fatalln(err) + } + if d != nil { + return + } + defer daemonContext.Release() } - defer daemonContext.Release() - go worker(parentCtx, logger, *loadedConfig) + go worker(parentCtx, logger, loadedConfig) err = daemon.ServeSignals() if err != nil {