Created
January 19, 2016 19:41
-
-
Save lanrat/8a8b385959627a7b29f1 to your computer and use it in GitHub Desktop.
Recreate a docker container with the same configuration after an image upgrade
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"os" | |
"strings" | |
"github.com/fsouza/go-dockerclient" | |
//"github.com/tonnerre/golang-pretty" | |
) | |
func check(err error) { | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(0) | |
} | |
} | |
func main() { | |
if len(os.Args) != 2 { | |
fmt.Printf("Usage: %s [Container ID]\n", os.Args[0]) | |
os.Exit(0) | |
} | |
/* | |
also have option to build locally, or retirieve docker file and built rather than pull | |
Steps: | |
* Pull new if from remote | |
* Save old config | |
* Make new container | |
* Rename old | |
* stop old if started | |
* start new if old is running | |
* option: delete old if sucsessfull | |
* if error rename old to origional name, and put back in origional state | |
*/ | |
endpoint := "unix:///var/run/docker.sock" | |
client, _ := docker.NewClient(endpoint) | |
// get container info | |
old_container, err := client.InspectContainer(os.Args[1]) | |
check(err) | |
//TODO delete _new if an error occores | |
// pull new image | |
//TODO | |
// also need to ensure we use the latest version of the iamge when building? | |
// TODO check to make sure rebuilt container is using updated image | |
fmt.Printf("Image: %s\n", old_container.Config.Image) | |
// get image data | |
//TODO handle image tags/labels? | |
// naming | |
name := old_container.Name | |
tmp_name := name+"_new" | |
// copy container | |
var options docker.CreateContainerOptions | |
options.Name = tmp_name | |
options.Config = old_container.Config | |
options.HostConfig = old_container.HostConfig | |
// get all vomumes | |
//options.HostConfig.VolumesFrom = append(options.HostConfig.VolumesFrom, old_container.ID) | |
options.HostConfig.VolumesFrom = []string{old_container.ID} | |
// get all links | |
// this is a hack to fix the way links are returned and sent | |
links := old_container.HostConfig.Links | |
for i := range links { | |
parts := strings.SplitN(links[i], ":", 2) | |
if len(parts) != 2 { | |
fmt.Println("Unable to parse link ", links[i]) | |
// TODO make function and add better error return | |
return | |
} | |
container_name := strings.TrimPrefix(parts[0], "/") | |
alias_parts := strings.Split(parts[1], "/") | |
alias := alias_parts[len(alias_parts)-1] | |
links[i] = fmt.Sprintf("%s:%s", container_name, alias) | |
} | |
options.HostConfig.Links = links | |
fmt.Println("Creating...") | |
new_container, err := client.CreateContainer(options) | |
check(err) | |
// rename | |
err = client.RenameContainer(docker.RenameContainerOptions{ID:old_container.ID, Name:name+"_old"}) | |
check(err) | |
err = client.RenameContainer(docker.RenameContainerOptions{ID:new_container.ID, Name:name}) | |
check(err) | |
if old_container.State.Running { | |
fmt.Printf("Stopping old container\n") | |
err = client.StopContainer(old_container.ID, 10) | |
check(err) | |
fmt.Printf("Starting new container\n") | |
err = client.StartContainer(new_container.ID, new_container.HostConfig) | |
check(err) | |
} | |
// add optionn to rm old container on sucsess | |
fmt.Printf("Migrated from %s to %s\n", old_container.ID, new_container.ID) | |
fmt.Println("Done") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment