mirror of https://github.com/docker/compose.git
Merge pull request #845 from docker/add-aci-healthcheck
Add Healthchecks to ACI
This commit is contained in:
commit
af1dae52eb
|
@ -40,6 +40,7 @@ func ContainerToComposeProject(r containers.ContainerConfig) (types.Project, err
|
|||
return types.Project{}, err
|
||||
}
|
||||
|
||||
retries := uint64(r.Healthcheck.Retries)
|
||||
project := types.Project{
|
||||
Name: r.ID,
|
||||
Services: []types.ServiceConfig{
|
||||
|
@ -52,6 +53,14 @@ func ContainerToComposeProject(r containers.ContainerConfig) (types.Project, err
|
|||
Volumes: serviceConfigVolumes,
|
||||
DomainName: r.DomainName,
|
||||
Environment: toComposeEnvs(r.Environment),
|
||||
HealthCheck: &types.HealthCheckConfig{
|
||||
Test: r.Healthcheck.Test,
|
||||
Timeout: &r.Healthcheck.Timeout,
|
||||
Interval: &r.Healthcheck.Interval,
|
||||
Retries: &retries,
|
||||
StartPeriod: &r.Healthcheck.StartPeriod,
|
||||
Disable: r.Healthcheck.Disable,
|
||||
},
|
||||
Deploy: &types.DeployConfig{
|
||||
Resources: types.Resources{
|
||||
Reservations: &types.Resource{
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
|
@ -68,7 +69,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
|
|||
return containerinstance.ContainerGroup{}, err
|
||||
}
|
||||
|
||||
var containers []containerinstance.Container
|
||||
var ctnrs []containerinstance.Container
|
||||
restartPolicy, err := project.getRestartPolicy()
|
||||
if err != nil {
|
||||
return containerinstance.ContainerGroup{}, err
|
||||
|
@ -78,7 +79,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
|
|||
Location: &aciContext.Location,
|
||||
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
|
||||
OsType: containerinstance.Linux,
|
||||
Containers: &containers,
|
||||
Containers: &ctnrs,
|
||||
Volumes: volumes,
|
||||
ImageRegistryCredentials: ®istryCreds,
|
||||
RestartPolicy: restartPolicy,
|
||||
|
@ -110,7 +111,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
|
|||
dnsLabelName = serviceDomainName
|
||||
}
|
||||
|
||||
containers = append(containers, containerDefinition)
|
||||
ctnrs = append(ctnrs, containerDefinition)
|
||||
}
|
||||
if len(groupPorts) > 0 {
|
||||
groupDefinition.ContainerGroupProperties.IPAddress = &containerinstance.IPAddress{
|
||||
|
@ -119,15 +120,23 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
|
|||
DNSNameLabel: dnsLabelName,
|
||||
}
|
||||
}
|
||||
if len(containers) > 1 {
|
||||
dnsSideCar := getDNSSidecar(containers)
|
||||
containers = append(containers, dnsSideCar)
|
||||
if len(ctnrs) > 1 {
|
||||
dnsSideCar := getDNSSidecar(ctnrs)
|
||||
ctnrs = append(ctnrs, dnsSideCar)
|
||||
}
|
||||
groupDefinition.ContainerGroupProperties.Containers = &containers
|
||||
groupDefinition.ContainerGroupProperties.Containers = &ctnrs
|
||||
|
||||
return groupDefinition, nil
|
||||
}
|
||||
|
||||
func durationToSeconds(d *types.Duration) *int32 {
|
||||
if d == nil || *d == 0 {
|
||||
return nil
|
||||
}
|
||||
v := int32(time.Duration(*d).Seconds())
|
||||
return &v
|
||||
}
|
||||
|
||||
func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
|
||||
names := []string{"/hosts"}
|
||||
for _, container := range containers {
|
||||
|
@ -181,6 +190,7 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c
|
|||
EnvironmentVariables: getEnvVariables(s.Environment),
|
||||
Resources: resource,
|
||||
VolumeMounts: volumes,
|
||||
LivenessProbe: s.getLivenessProbe(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -237,6 +247,38 @@ func (s serviceConfigAciHelper) getResourceRequestsLimits() (*containerinstance.
|
|||
return &resources, nil
|
||||
}
|
||||
|
||||
func (s serviceConfigAciHelper) getLivenessProbe() *containerinstance.ContainerProbe {
|
||||
if s.HealthCheck != nil && !s.HealthCheck.Disable && len(s.HealthCheck.Test) > 0 {
|
||||
testArray := s.HealthCheck.Test
|
||||
switch s.HealthCheck.Test[0] {
|
||||
case "NONE", "CMD", "CMD-SHELL":
|
||||
testArray = s.HealthCheck.Test[1:]
|
||||
}
|
||||
if len(testArray) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var retries *int32
|
||||
if s.HealthCheck.Retries != nil {
|
||||
retries = to.Int32Ptr(int32(*s.HealthCheck.Retries))
|
||||
}
|
||||
probe := containerinstance.ContainerProbe{
|
||||
Exec: &containerinstance.ContainerExec{
|
||||
Command: to.StringSlicePtr(testArray),
|
||||
},
|
||||
InitialDelaySeconds: durationToSeconds(s.HealthCheck.StartPeriod),
|
||||
PeriodSeconds: durationToSeconds(s.HealthCheck.Interval),
|
||||
TimeoutSeconds: durationToSeconds(s.HealthCheck.Timeout),
|
||||
}
|
||||
if retries != nil && *retries > 0 {
|
||||
probe.FailureThreshold = retries
|
||||
probe.SuccessThreshold = retries
|
||||
}
|
||||
return &probe
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEnvVariables(composeEnv types.MappingWithEquals) *[]containerinstance.EnvironmentVariable {
|
||||
result := []containerinstance.EnvironmentVariable{}
|
||||
for key, value := range composeEnv {
|
||||
|
@ -310,6 +352,31 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
|
|||
FQDN: fqdn(cg, region),
|
||||
Env: envVars,
|
||||
}
|
||||
|
||||
var healthcheck = containers.Healthcheck{
|
||||
Disable: true,
|
||||
}
|
||||
if cc.LivenessProbe != nil &&
|
||||
cc.LivenessProbe.Exec != nil &&
|
||||
cc.LivenessProbe.Exec.Command != nil {
|
||||
if len(*cc.LivenessProbe.Exec.Command) > 0 {
|
||||
healthcheck.Disable = false
|
||||
healthcheck.Test = *cc.LivenessProbe.Exec.Command
|
||||
if cc.LivenessProbe.PeriodSeconds != nil {
|
||||
healthcheck.Interval = types.Duration(int64(*cc.LivenessProbe.PeriodSeconds) * int64(time.Second))
|
||||
}
|
||||
if cc.LivenessProbe.SuccessThreshold != nil {
|
||||
healthcheck.Retries = int(*cc.LivenessProbe.SuccessThreshold)
|
||||
}
|
||||
if cc.LivenessProbe.TimeoutSeconds != nil {
|
||||
healthcheck.Timeout = types.Duration(int64(*cc.LivenessProbe.TimeoutSeconds) * int64(time.Second))
|
||||
}
|
||||
if cc.LivenessProbe.InitialDelaySeconds != nil {
|
||||
healthcheck.StartPeriod = types.Duration(int64(*cc.LivenessProbe.InitialDelaySeconds) * int64(time.Second))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c := containers.Container{
|
||||
ID: containerID,
|
||||
Status: status,
|
||||
|
@ -323,6 +390,7 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
|
|||
Platform: platform,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
Healthcheck: healthcheck,
|
||||
}
|
||||
|
||||
return c
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
|
@ -88,6 +89,19 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||
MemoryInGB: to.Float64Ptr(0.1),
|
||||
},
|
||||
},
|
||||
LivenessProbe: &containerinstance.ContainerProbe{
|
||||
Exec: &containerinstance.ContainerExec{
|
||||
Command: to.StringSlicePtr([]string{
|
||||
"my",
|
||||
"command",
|
||||
"--option",
|
||||
}),
|
||||
},
|
||||
PeriodSeconds: to.Int32Ptr(10),
|
||||
SuccessThreshold: to.Int32Ptr(3),
|
||||
InitialDelaySeconds: to.Int32Ptr(2),
|
||||
TimeoutSeconds: to.Int32Ptr(1),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -113,12 +127,111 @@ func TestContainerGroupToContainer(t *testing.T) {
|
|||
MemoryReservation: gbToBytes(0.1),
|
||||
RestartPolicy: "any",
|
||||
},
|
||||
Healthcheck: containers.Healthcheck{
|
||||
Disable: false,
|
||||
Test: []string{
|
||||
"my",
|
||||
"command",
|
||||
"--option",
|
||||
},
|
||||
Interval: types.Duration(10 * time.Second),
|
||||
Retries: 3,
|
||||
StartPeriod: types.Duration(2 * time.Second),
|
||||
Timeout: types.Duration(time.Second),
|
||||
},
|
||||
}
|
||||
|
||||
container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer, "eastus")
|
||||
assert.DeepEqual(t, container, expectedContainer)
|
||||
}
|
||||
|
||||
func TestHealthcheckTranslation(t *testing.T) {
|
||||
test := []string{
|
||||
"my",
|
||||
"command",
|
||||
"--option",
|
||||
}
|
||||
interval := types.Duration(10 * time.Second)
|
||||
retries := uint64(42)
|
||||
startPeriod := types.Duration(2 * time.Second)
|
||||
timeout := types.Duration(3 * time.Second)
|
||||
project := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "service1",
|
||||
Image: "image1",
|
||||
HealthCheck: &types.HealthCheckConfig{
|
||||
Test: test,
|
||||
Timeout: &timeout,
|
||||
Interval: &interval,
|
||||
Retries: &retries,
|
||||
StartPeriod: &startPeriod,
|
||||
Disable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testHealthcheckTestPrefixRemoval := func(test []string, shellPreffix ...string) {
|
||||
project.Services[0].HealthCheck.Test = append(shellPreffix, test...)
|
||||
group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, (*group.Containers)[0].LivenessProbe.Exec.Command, to.StringSlicePtr(test))
|
||||
assert.Equal(t, *(*group.Containers)[0].LivenessProbe.PeriodSeconds, int32(10))
|
||||
assert.Equal(t, *(*group.Containers)[0].LivenessProbe.SuccessThreshold, int32(42))
|
||||
assert.Equal(t, *(*group.Containers)[0].LivenessProbe.FailureThreshold, int32(42))
|
||||
assert.Equal(t, *(*group.Containers)[0].LivenessProbe.InitialDelaySeconds, int32(2))
|
||||
assert.Equal(t, *(*group.Containers)[0].LivenessProbe.TimeoutSeconds, int32(3))
|
||||
}
|
||||
|
||||
testHealthcheckTestPrefixRemoval(test)
|
||||
testHealthcheckTestPrefixRemoval(test, "NONE")
|
||||
testHealthcheckTestPrefixRemoval(test, "CMD")
|
||||
testHealthcheckTestPrefixRemoval(test, "CMD-SHELL")
|
||||
|
||||
project.Services[0].HealthCheck.Disable = true
|
||||
group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe == nil)
|
||||
}
|
||||
|
||||
func TestHealthcheckTranslationZeroValues(t *testing.T) {
|
||||
test := []string{
|
||||
"my",
|
||||
"command",
|
||||
"--option",
|
||||
}
|
||||
interval := types.Duration(0)
|
||||
retries := uint64(0)
|
||||
startPeriod := types.Duration(0)
|
||||
timeout := types.Duration(0)
|
||||
|
||||
project := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "service1",
|
||||
Image: "image1",
|
||||
HealthCheck: &types.HealthCheckConfig{
|
||||
Test: test,
|
||||
Timeout: &timeout,
|
||||
Interval: &interval,
|
||||
Retries: &retries,
|
||||
StartPeriod: &startPeriod,
|
||||
Disable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, (*group.Containers)[0].LivenessProbe.Exec.Command, to.StringSlicePtr(test))
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe.PeriodSeconds == nil)
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe.SuccessThreshold == nil)
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe.FailureThreshold == nil)
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe.InitialDelaySeconds == nil)
|
||||
assert.Assert(t, (*group.Containers)[0].LivenessProbe.TimeoutSeconds == nil)
|
||||
}
|
||||
|
||||
func TestContainerGroupToServiceStatus(t *testing.T) {
|
||||
myContainerGroup := containerinstance.ContainerGroup{
|
||||
ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
|
||||
"github.com/docker/compose-cli/formatter"
|
||||
)
|
||||
|
||||
|
@ -54,6 +56,7 @@ type Container struct {
|
|||
HostConfig *HostConfig `json:",omitempty"`
|
||||
Ports []Port `json:",omitempty"`
|
||||
Platform string
|
||||
Healthcheck Healthcheck
|
||||
}
|
||||
|
||||
// RuntimeConfig config of a created container
|
||||
|
@ -112,6 +115,24 @@ type ContainerConfig struct {
|
|||
DomainName string
|
||||
// AutoRemove sets the container to be removed automatically when stopped
|
||||
AutoRemove bool
|
||||
// Healthcheck contains the command and interval of the checks
|
||||
Healthcheck Healthcheck
|
||||
}
|
||||
|
||||
// Healthcheck defines the configuration of a healthcheck
|
||||
type Healthcheck struct {
|
||||
// Disable disables the check
|
||||
Disable bool
|
||||
// Test is the command to be run to check the health of the container
|
||||
Test []string
|
||||
// Interval is the period in between the checks
|
||||
Interval types.Duration
|
||||
// Retries is the number of attempts before declaring the container as healthy or unhealthy
|
||||
Retries int
|
||||
// StartPeriod is the start delay before starting the checks
|
||||
StartPeriod types.Duration
|
||||
// Timeout is the timeout in between checks
|
||||
Timeout types.Duration
|
||||
}
|
||||
|
||||
// ExecRequest contaiens configuration about an exec request
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -59,6 +60,12 @@ func Command(contextType string) *cobra.Command {
|
|||
cmd.Flags().StringArrayVar(&opts.EnvironmentFiles, "env-file", []string{}, "Path to environment files to be translated as environment variables")
|
||||
cmd.Flags().StringVarP(&opts.RestartPolicyCondition, "restart", "", containers.RestartPolicyRunNo, "Restart policy to apply when a container exits (no|always|on-failure)")
|
||||
cmd.Flags().BoolVar(&opts.Rm, "rm", false, "Automatically remove the container when it exits")
|
||||
cmd.Flags().StringVar(&opts.HealthCmd, "health-cmd", "", "Command to run to check health")
|
||||
cmd.Flags().DurationVar(&opts.HealthInterval, "health-interval", time.Duration(0), "Time between running the check (ms|s|m|h) (default 0s)")
|
||||
cmd.Flags().IntVar(&opts.HealthRetries, "health-retries", 10, "Consecutive failures needed to report unhealthy")
|
||||
cmd.Flags().DurationVar(&opts.HealthStartPeriod, "health-start-period", time.Duration(0), "Start period for the container to initialize before starting "+
|
||||
"health-retries countdown (ms|s|m|h) (default 0s)")
|
||||
cmd.Flags().DurationVar(&opts.HealthTimeout, "health-timeout", time.Duration(0), "Maximum time to allow one check to run (ms|s|m|h) (default 0s)")
|
||||
|
||||
if contextType == store.AciContextType {
|
||||
cmd.Flags().StringVar(&opts.DomainName, "domainname", "", "Container NIS domain name")
|
||||
|
|
|
@ -4,14 +4,19 @@ Usage:
|
|||
run [flags]
|
||||
|
||||
Flags:
|
||||
--cpus float Number of CPUs (default 1)
|
||||
-d, --detach Run container in background and print container ID
|
||||
--domainname string Container NIS domain name
|
||||
-e, --env stringArray Set environment variables
|
||||
--env-file stringArray Path to environment files to be translated as environment variables
|
||||
-l, --label stringArray Set meta data on a container
|
||||
-m, --memory bytes Memory limit
|
||||
--name string Assign a name to the container
|
||||
-p, --publish stringArray Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT
|
||||
--restart string Restart policy to apply when a container exits (no|always|on-failure) (default "no")
|
||||
-v, --volume stringArray Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]
|
||||
--cpus float Number of CPUs (default 1)
|
||||
-d, --detach Run container in background and print container ID
|
||||
--domainname string Container NIS domain name
|
||||
-e, --env stringArray Set environment variables
|
||||
--env-file stringArray Path to environment files to be translated as environment variables
|
||||
--health-cmd string Command to run to check health
|
||||
--health-interval duration Time between running the check (ms|s|m|h) (default 0s)
|
||||
--health-retries int Consecutive failures needed to report unhealthy (default 10)
|
||||
--health-start-period duration Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)
|
||||
--health-timeout duration Maximum time to allow one check to run (ms|s|m|h) (default 0s)
|
||||
-l, --label stringArray Set meta data on a container
|
||||
-m, --memory bytes Memory limit
|
||||
--name string Assign a name to the container
|
||||
-p, --publish stringArray Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT
|
||||
--restart string Restart policy to apply when a container exits (no|always|on-failure) (default "no")
|
||||
-v, --volume stringArray Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]
|
||||
|
|
|
@ -15,5 +15,13 @@
|
|||
"MemoryLimit": 0,
|
||||
"AutoRemove": false
|
||||
},
|
||||
"Platform": "Linux"
|
||||
"Platform": "Linux",
|
||||
"Healthcheck": {
|
||||
"Disable": false,
|
||||
"Test": null,
|
||||
"Interval": "0s",
|
||||
"Retries": 0,
|
||||
"StartPeriod": "0s",
|
||||
"Timeout": "0s"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/pkg/namesgenerator"
|
||||
"github.com/docker/go-connections/nat"
|
||||
|
@ -44,6 +46,11 @@ type Opts struct {
|
|||
RestartPolicyCondition string
|
||||
DomainName string
|
||||
Rm bool
|
||||
HealthCmd string
|
||||
HealthInterval time.Duration
|
||||
HealthRetries int
|
||||
HealthStartPeriod time.Duration
|
||||
HealthTimeout time.Duration
|
||||
}
|
||||
|
||||
// ToContainerConfig convert run options to a container configuration
|
||||
|
@ -76,6 +83,13 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
|
|||
envVars = append(envVars, vars...)
|
||||
}
|
||||
|
||||
var healthCmd []string
|
||||
var healthInterval types.Duration
|
||||
if len(r.HealthCmd) > 0 {
|
||||
healthCmd = strings.Split(r.HealthCmd, " ")
|
||||
healthInterval = types.Duration(r.HealthInterval)
|
||||
}
|
||||
|
||||
return containers.ContainerConfig{
|
||||
ID: r.Name,
|
||||
Image: image,
|
||||
|
@ -89,6 +103,11 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
|
|||
RestartPolicyCondition: restartPolicy,
|
||||
DomainName: r.DomainName,
|
||||
AutoRemove: r.Rm,
|
||||
Healthcheck: containers.Healthcheck{
|
||||
Disable: len(healthCmd) == 0,
|
||||
Test: healthCmd,
|
||||
Interval: healthInterval,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ __Legend:__
|
|||
| service.external_links | x |
|
||||
| service.extra_hosts | x |
|
||||
| service.group_add | x |
|
||||
| service.healthcheck | n |
|
||||
| service.healthcheck | ✓ |
|
||||
| service.hostname | x |
|
||||
| service.image | ✓ | Private images will be accessible if the user is logged into the corresponding registry at deploy time. Users will be automatically logged in to Azure Container Registry using their Azure login if possible.
|
||||
| service.isolation | x |
|
||||
|
@ -209,3 +209,21 @@ services:
|
|||
|
||||
In this example, the db container will be allocated 2 CPUs and 2G of memory. It will be allowed to use up to 3 CPUs and 3G of memory, using some of the resources allocated to the web container.
|
||||
The web container will have its limits set to the same values as reservations, by default.
|
||||
|
||||
## Healthchecks
|
||||
|
||||
Healthchecks can be described in the `healthcheck` section in the service. It translates to `LivenessProbe` in ACI. By that, the container is restarted if it becomes unhealthy.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
```
|
||||
|
||||
**Note:** that the `test` command can be a `string` or an array starting or not by `NONE`, `CMD`, `CMD-SHELL`. In the ACI implementation, these prefixes are ignored.
|
2
go.mod
2
go.mod
|
@ -22,7 +22,7 @@ require (
|
|||
github.com/aws/aws-sdk-go v1.35.15
|
||||
github.com/awslabs/goformation/v4 v4.15.3
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||
github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209
|
||||
github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35
|
||||
github.com/containerd/console v1.0.1
|
||||
github.com/containerd/containerd v1.3.5 // indirect
|
||||
github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8
|
||||
|
|
5
go.sum
5
go.sum
|
@ -122,8 +122,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
|||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209 h1:PLZiS7hjkiAqZYBRAEq3tbGlhCh6/R14dO1ahwbEIBg=
|
||||
github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209/go.mod h1:rNXXqhdClEljsNb6QDIOqTQaRfigwTgGZZM6Zpr3LeY=
|
||||
github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35 h1:HLxSiPmzCkBi3mGgxHQGBi3vxUuzT72Q9xjG49hkvSA=
|
||||
github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35/go.mod h1:cBdHyUvAothdUpqXANCfTHU7cEqsXRvSiLxjhOTuwvc=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
|
@ -516,6 +516,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMc
|
|||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56 h1:yhqBHs09SmmUoNOHc9jgK4a60T3XFRtPAkYxVnqgY50=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@ message Container {
|
|||
repeated Port ports = 11;
|
||||
string platform = 13;
|
||||
HostConfig host_config = 15;
|
||||
Healthcheck healthcheck = 16;
|
||||
}
|
||||
|
||||
message HostConfig {
|
||||
|
@ -62,6 +63,12 @@ message HostConfig {
|
|||
bool auto_remove = 6;
|
||||
}
|
||||
|
||||
message Healthcheck {
|
||||
bool disable = 1;
|
||||
repeated string test = 2;
|
||||
int64 interval = 3;
|
||||
}
|
||||
|
||||
message InspectRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
@ -113,6 +120,7 @@ message RunRequest {
|
|||
repeated string command = 9;
|
||||
repeated string environment = 10;
|
||||
bool auto_remove = 11;
|
||||
Healthcheck healthcheck = 12;
|
||||
}
|
||||
|
||||
message RunResponse {
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/formatter"
|
||||
containersv1 "github.com/docker/compose-cli/protos/containers/v1"
|
||||
|
@ -141,6 +143,11 @@ func toGrpcContainer(c containers.Container) *containersv1.Container {
|
|||
RestartPolicy: c.HostConfig.RestartPolicy,
|
||||
AutoRemove: c.HostConfig.AutoRemove,
|
||||
},
|
||||
Healthcheck: &containersv1.Healthcheck{
|
||||
Disable: c.Healthcheck.Disable,
|
||||
Test: c.Healthcheck.Test,
|
||||
Interval: int64(c.Healthcheck.Interval),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,5 +174,10 @@ func grpcContainerToContainerConfig(request *containersv1.RunRequest) containers
|
|||
RestartPolicyCondition: request.RestartPolicyCondition,
|
||||
Environment: request.Environment,
|
||||
AutoRemove: request.AutoRemove,
|
||||
Healthcheck: containers.Healthcheck{
|
||||
Disable: request.GetHealthcheck().GetDisable(),
|
||||
Test: request.GetHealthcheck().GetTest(),
|
||||
Interval: types.Duration(request.GetHealthcheck().GetInterval()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,5 +15,13 @@
|
|||
"MemoryLimit": 0,
|
||||
"AutoRemove": false
|
||||
},
|
||||
"Platform": "Linux"
|
||||
"Platform": "Linux",
|
||||
"Healthcheck": {
|
||||
"Disable": false,
|
||||
"Test": null,
|
||||
"Interval": "0s",
|
||||
"Retries": 0,
|
||||
"StartPeriod": "0s",
|
||||
"Timeout": "0s"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue