Skip to content

Commit 7bb0ffa

Browse files
author
richardpen
committed
engine: Make the agent reuse the generated container name on restart
Save the generated docker container name and when agent restart restore the agent state, when agent try to create the container it will reuse the name so that no duplicate container will be created.
1 parent f8caf08 commit 7bb0ffa

File tree

4 files changed

+80
-25
lines changed

4 files changed

+80
-25
lines changed

agent/engine/docker_container_engine.go

+10
Original file line numberDiff line numberDiff line change
@@ -468,10 +468,20 @@ func (dg *dockerGoClient) startContainer(ctx context.Context, id string) DockerC
468468
return metadata
469469
}
470470

471+
// https://github.com/fsouza/go-dockerclient/blob/fd53184a1439b6d7b82ca54c1cd9adac9a5278f2/container.go#L197
471472
func dockerStateToState(state docker.State) api.ContainerStatus {
472473
if state.Running {
473474
return api.ContainerRunning
474475
}
476+
477+
if state.Dead {
478+
return api.ContainerStopped
479+
}
480+
481+
if state.StartedAt.IsZero() {
482+
return api.ContainerCreated
483+
}
484+
475485
return api.ContainerStopped
476486
}
477487

agent/engine/docker_task_engine.go

+33-21
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ func (engine *DockerTaskEngine) synchronizeState() {
236236
log.Warn("Could not find matching container for expected", "name", cont.DockerName)
237237
} else {
238238
cont.DockerID = describedCont.ID
239+
cont.Container.SetKnownStatus(dockerStateToState(describedCont.State))
239240
// update mappings that need dockerid
240241
engine.state.AddContainer(cont, task)
241242
engine.imageManager.RecordContainerReference(cont.Container)
@@ -558,15 +559,24 @@ func (engine *DockerTaskEngine) createContainer(task *api.Task, container *api.C
558559
client = client.WithVersion(dockerclient.DockerVersion(*container.DockerConfig.Version))
559560
}
560561

561-
// Resolve HostConfig
562-
// we have to do this in create, not start, because docker no longer handles
563-
// merging create config with start hostconfig the same; e.g. memory limits
564-
// get lost
562+
dockerContainerName := ""
565563
containerMap, ok := engine.state.ContainerMapByArn(task.Arn)
566564
if !ok {
567565
containerMap = make(map[string]*api.DockerContainer)
566+
} else {
567+
// looking for container that has docker name but not created
568+
for _, v := range containerMap {
569+
if v.Container.Name == container.Name {
570+
dockerContainerName = v.DockerName
571+
break
572+
}
573+
}
568574
}
569575

576+
// Resolve HostConfig
577+
// we have to do this in create, not start, because docker no longer handles
578+
// merging create config with start hostconfig the same; e.g. memory limits
579+
// get lost
570580
hostConfig, hcerr := task.DockerHostConfig(container, containerMap)
571581
if hcerr != nil {
572582
return DockerContainerMetadata{Error: api.NamedError(hcerr)}
@@ -586,28 +596,30 @@ func (engine *DockerTaskEngine) createContainer(task *api.Task, container *api.C
586596
config.Labels[labelPrefix+"task-definition-version"] = task.Version
587597
config.Labels[labelPrefix+"cluster"] = engine.cfg.Cluster
588598

589-
name := ""
590-
for i := 0; i < len(container.Name); i++ {
591-
c := container.Name[i]
592-
if !((c <= '9' && c >= '0') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '-')) {
593-
continue
599+
if dockerContainerName == "" {
600+
name := ""
601+
for i := 0; i < len(container.Name); i++ {
602+
c := container.Name[i]
603+
if !((c <= '9' && c >= '0') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '-')) {
604+
continue
605+
}
606+
name += string(c)
594607
}
595-
name += string(c)
596-
}
597608

598-
containerName := "ecs-" + task.Family + "-" + task.Version + "-" + name + "-" + utils.RandHex()
609+
dockerContainerName = "ecs-" + task.Family + "-" + task.Version + "-" + name + "-" + utils.RandHex()
599610

600-
// Pre-add the container in case we stop before the next, more useful,
601-
// AddContainer call. This ensures we have a way to get the container if
602-
// we die before 'createContainer' returns because we can inspect by
603-
// name
604-
engine.state.AddContainer(&api.DockerContainer{DockerName: containerName, Container: container}, task)
605-
seelog.Infof("Created container name mapping for task %s - %s -> %s", task, container, containerName)
606-
engine.saver.ForceSave()
611+
// Pre-add the container in case we stop before the next, more useful,
612+
// AddContainer call. This ensures we have a way to get the container if
613+
// we die before 'createContainer' returns because we can inspect by
614+
// name
615+
engine.state.AddContainer(&api.DockerContainer{DockerName: dockerContainerName, Container: container}, task)
616+
seelog.Infof("Created container name mapping for task %s - %s -> %s", task, container, dockerContainerName)
617+
engine.saver.ForceSave()
618+
}
607619

608-
metadata := client.CreateContainer(config, hostConfig, containerName, createContainerTimeout)
620+
metadata := client.CreateContainer(config, hostConfig, dockerContainerName, createContainerTimeout)
609621
if metadata.DockerID != "" {
610-
engine.state.AddContainer(&api.DockerContainer{DockerID: metadata.DockerID, DockerName: containerName, Container: container}, task)
622+
engine.state.AddContainer(&api.DockerContainer{DockerID: metadata.DockerID, DockerName: dockerContainerName, Container: container}, task)
611623
}
612624
seelog.Infof("Created docker container for task %s: %s -> %s", task, container, metadata.DockerID)
613625
return metadata

agent/engine/docker_task_engine_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -1203,3 +1203,29 @@ func TestTaskWithCircularDependency(t *testing.T) {
12031203
_, ok = taskEngine.(*DockerTaskEngine).managedTasks[task.Arn]
12041204
assert.False(t, ok, "Task should not be added to task manager for processing")
12051205
}
1206+
1207+
// TestCreateContainerOnAgentRestart tests when agent restarts it should use the
1208+
// docker container name restored from agent state file to create the container
1209+
func TestCreateContainerOnAgentRestart(t *testing.T) {
1210+
ctrl, client, _, privateTaskEngine, _, _ := mocks(t, &config.Config{})
1211+
saver := mock_statemanager.NewMockStateManager(ctrl)
1212+
defer ctrl.Finish()
1213+
1214+
taskEngine, _ := privateTaskEngine.(*DockerTaskEngine)
1215+
taskEngine.SetSaver(saver)
1216+
state := taskEngine.State()
1217+
1218+
sleepTask := testdata.LoadTask("sleep5")
1219+
sleepContainer, _ := sleepTask.ContainerByName("sleep5")
1220+
// Store the generated container name to state
1221+
state.AddContainer(&api.DockerContainer{DockerName: "docker_container_name", Container: sleepContainer}, sleepTask)
1222+
1223+
gomock.InOrder(
1224+
client.EXPECT().CreateContainer(gomock.Any(), gomock.Any(), "docker_container_name", gomock.Any()),
1225+
)
1226+
1227+
metadata := taskEngine.createContainer(sleepTask, sleepContainer)
1228+
if metadata.Error != nil {
1229+
t.Error("Unexpected error", metadata.Error)
1230+
}
1231+
}

agent/engine/dockerstate/docker_task_engine_state.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -250,18 +250,25 @@ func (state *DockerTaskEngineState) AddContainer(container *api.DockerContainer,
250250
}
251251

252252
if container.DockerID != "" {
253+
// Update the container id to the state
254+
state.idToContainer[container.DockerID] = container
253255
state.idToTask[container.DockerID] = task.Arn
256+
257+
// Remove the previously added name mapping
258+
delete(state.idToContainer, container.DockerName)
259+
delete(state.idToTask, container.DockerName)
260+
} else if container.DockerName != "" {
261+
// Update the container name mapping to the state when the ID isn't available
262+
state.idToContainer[container.DockerName] = container
263+
state.idToTask[container.DockerName] = task.Arn
254264
}
265+
255266
existingMap, exists := state.taskToID[task.Arn]
256267
if !exists {
257268
existingMap = make(map[string]*api.DockerContainer, len(task.Containers))
258269
state.taskToID[task.Arn] = existingMap
259270
}
260271
existingMap[container.Container.Name] = container
261-
262-
if container.DockerID != "" {
263-
state.idToContainer[container.DockerID] = container
264-
}
265272
}
266273

267274
// AddImageState adds an image.ImageState to be stored

0 commit comments

Comments
 (0)