/
config.go
161 lines (141 loc) · 4.57 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package main
import (
"log"
"os"
"strconv"
"time"
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
"gopkg.in/yaml.v2"
)
type Config struct {
Containers map[string]*Container
// Containers will be checked periodically with this interval value to match the definitions in config file.
// Config file does not get read on every check interval. It only gets read on startup and when SIGHUP is received.
CheckInterval time.Duration
// HTTP server runs on this address for /health endpoint.
ListenAddr string
}
type Container struct {
// Running container will get replaced only if version changes.
// You should update this value for every deploy.
// Usually you should set a value such as build number from your CI tool.
Version string
// Number of running copies of this container.
// An index number will be appended to the container name after first container.
// Example: ["foo", "foo.2", "foo.3", "foo.4"]
Count uint
// Command to run on each CheckInterval to determine if the container is healty.
CheckCmd []string
// Timeout for CheckCmd. Command must exit with 0 in CheckTimeout.
CheckTimeout time.Duration
// Following options are passed directly to the Docker Engine API when creating the container.
Image string
WorkingDir string
Entrypoint []string
Cmd []string
StopSignal string
StopTimeout time.Duration
NetworkMode string
Hostname string
Env map[string]string
Binds []string
PortBindings nat.PortMap
LogConfig container.LogConfig
Resources container.Resources
}
func (c *Config) setDefaults() {
if c.CheckInterval <= 0 {
c.CheckInterval = defaultCheckInterval
}
if c.ListenAddr == "" {
c.ListenAddr = "127.0.0.1:26662"
}
}
func readConfig() error {
log.Println("loading config from:", *configPath)
f, err := os.Open(*configPath)
if err != nil {
return err
}
defer f.Close()
var c Config
err = yaml.NewDecoder(f).Decode(&c)
if err != nil {
return err
}
c.setDefaults()
mu.Lock()
defer mu.Unlock()
cfg = c
definitions = make(map[string]*Container, len(cfg.Containers))
for name, con := range cfg.Containers {
con.setDefaults()
const start = 1
for i := uint(start); i < con.Count+start; i++ {
if i == start {
definitions[name] = con
} else {
definitions[name+"."+strconv.FormatUint(uint64(i), 10)] = con
}
}
}
return nil
}
func (con *Container) setDefaults() {
if con.Count == 0 {
con.Count = 1
}
if len(con.CheckCmd) == 0 {
con.CheckCmd = []string{"ls", "/"}
}
if con.CheckTimeout == 0 {
con.CheckTimeout = 10 * time.Second
}
}
func getContainerDefinion(name string) *Container {
mu.Lock()
defer mu.Unlock()
return definitions[name]
}
func getCheckInterval() time.Duration {
mu.Lock()
defer mu.Unlock()
return cfg.CheckInterval
}
func (c *Container) dockerConfig() *container.Config {
env := make([]string, 0, len(c.Env))
for k, v := range c.Env {
env = append(env, k+"="+v)
}
var stopTimeout *int
if sec := int(c.StopTimeout / time.Second); sec > 0 {
stopTimeout = &sec
}
return &container.Config{
Hostname: c.Hostname,
AttachStdout: true, // Attach the standard output
AttachStderr: true, // Attach the standard error
Env: env, // List of environment variable to set in the container
Cmd: c.Cmd, // Command to run when starting the container
Image: c.Image, // Name of the image as it was passed by the operator (e.g. could be symbolic)
WorkingDir: c.WorkingDir, // Current directory (PWD) in the command will be launched
Entrypoint: c.Entrypoint, // Entrypoint to run when starting the container
StopSignal: c.StopSignal, // Signal to stop a container
StopTimeout: stopTimeout, // Timeout (in seconds) to stop a container
Labels: map[string]string{
containerVersionKey: c.Version,
}, // List of labels set to this container
}
}
func (c *Container) hostConfig() *container.HostConfig {
return &container.HostConfig{
Binds: c.Binds, // List of volume bindings for this container
PortBindings: c.PortBindings, // Port mapping between the exposed port (container) and the host
NetworkMode: container.NetworkMode(c.NetworkMode), // Network mode to use for the container
ExtraHosts: []string{"host.docker.internal:host-gateway"}, // List of extra hosts
RestartPolicy: container.RestartPolicy{Name: "unless-stopped"}, // Restart policy to be used for the container
LogConfig: c.LogConfig,
Resources: c.Resources,
}
}