Skip to content

Commit 183488f

Browse files
committed
Update checkpoint and restore to latest docker/master.
- C/R is now an EXPERIMENTAL level feature. - Requires CRIU 1.6 (and builds it from source in the Dockerfile) - Introduces checkpoint and restore as top level cli methods (will likely change) Signed-off-by: Ross Boucher <rboucher@gmail.com>
1 parent c19d362 commit 183488f

29 files changed

+786
-382
lines changed

Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /et
3232
# Packaged dependencies
3333
RUN apt-get update && apt-get install -y \
3434
apparmor \
35+
asciidoc \
3536
aufs-tools \
3637
automake \
3738
bash-completion \
39+
bsdmainutils \
3840
btrfs-tools \
3941
build-essential \
4042
createrepo \
@@ -43,21 +45,29 @@ RUN apt-get update && apt-get install -y \
4345
gcc-mingw-w64 \
4446
git \
4547
iptables \
48+
libaio-dev \
4649
libapparmor-dev \
4750
libcap-dev \
51+
libprotobuf-c0-dev \
52+
libprotobuf-dev \
4853
libsqlite3-dev \
4954
libsystemd-journal-dev \
5055
mercurial \
5156
parallel \
5257
pkg-config \
58+
protobuf-compiler \
59+
protobuf-c-compiler \
60+
python-minimal \
5361
python-mock \
5462
python-pip \
63+
python-protobuf \
5564
python-websocket \
5665
reprepro \
5766
ruby1.9.1 \
5867
ruby1.9.1-dev \
5968
s3cmd=1.1.0* \
6069
ubuntu-zfs \
70+
xmlto \
6171
libzfs-dev \
6272
--no-install-recommends
6373

@@ -82,6 +92,13 @@ RUN cd /usr/src/lxc \
8292
&& make install \
8393
&& ldconfig
8494

95+
# Install Criu
96+
RUN mkdir -p /usr/src/criu \
97+
&& curl -sSL https://github.com/xemul/criu/archive/v1.6.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1
98+
RUN cd /usr/src/criu \
99+
&& make \
100+
&& make install
101+
85102
# Install Go
86103
ENV GO_VERSION 1.4.3
87104
RUN curl -sSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/local -xz \

api/client/checkpoint.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// +build experimental
2+
3+
package client
4+
5+
import (
6+
"fmt"
7+
8+
Cli "github.com/docker/docker/cli"
9+
flag "github.com/docker/docker/pkg/mflag"
10+
"github.com/docker/docker/runconfig"
11+
)
12+
13+
// CmdCheckpoint checkpoints the process running in a container
14+
//
15+
// Usage: docker checkpoint CONTAINER
16+
func (cli *DockerCli) CmdCheckpoint(args ...string) error {
17+
cmd := Cli.Subcmd("checkpoint", []string{"CONTAINER [CONTAINER...]"}, "Checkpoint one or more running containers", true)
18+
cmd.Require(flag.Min, 1)
19+
20+
var (
21+
flImgDir = cmd.String([]string{"-image-dir"}, "", "directory for storing checkpoint image files")
22+
flWorkDir = cmd.String([]string{"-work-dir"}, "", "directory for storing log file")
23+
flLeaveRunning = cmd.Bool([]string{"-leave-running"}, false, "leave the container running after checkpoint")
24+
)
25+
26+
if err := cmd.ParseFlags(args, true); err != nil {
27+
return err
28+
}
29+
30+
if cmd.NArg() < 1 {
31+
cmd.Usage()
32+
return nil
33+
}
34+
35+
criuOpts := &runconfig.CriuConfig{
36+
ImagesDirectory: *flImgDir,
37+
WorkDirectory: *flWorkDir,
38+
LeaveRunning: *flLeaveRunning,
39+
TCPEstablished: true,
40+
ExternalUnixConnections: true,
41+
FileLocks: true,
42+
}
43+
44+
var encounteredError error
45+
for _, name := range cmd.Args() {
46+
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/checkpoint", criuOpts, nil))
47+
if err != nil {
48+
fmt.Fprintf(cli.err, "%s\n", err)
49+
encounteredError = fmt.Errorf("Error: failed to checkpoint one or more containers")
50+
} else {
51+
fmt.Fprintf(cli.out, "%s\n", name)
52+
}
53+
}
54+
return encounteredError
55+
}

api/client/restore.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// +build experimental
2+
3+
package client
4+
5+
import (
6+
"fmt"
7+
8+
Cli "github.com/docker/docker/cli"
9+
flag "github.com/docker/docker/pkg/mflag"
10+
"github.com/docker/docker/runconfig"
11+
)
12+
13+
// CmdRestore restores the process in a checkpointed container
14+
//
15+
// Usage: docker restore CONTAINER
16+
func (cli *DockerCli) CmdRestore(args ...string) error {
17+
cmd := Cli.Subcmd("restore", []string{"CONTAINER [CONTAINER...]"}, "Restore one or more checkpointed containers", true)
18+
cmd.Require(flag.Min, 1)
19+
20+
var (
21+
flImgDir = cmd.String([]string{"-image-dir"}, "", "directory to restore image files from")
22+
flWorkDir = cmd.String([]string{"-work-dir"}, "", "directory for restore log")
23+
flForce = cmd.Bool([]string{"-force"}, false, "bypass checks for current container state")
24+
)
25+
26+
if err := cmd.ParseFlags(args, true); err != nil {
27+
return err
28+
}
29+
30+
if cmd.NArg() < 1 {
31+
cmd.Usage()
32+
return nil
33+
}
34+
35+
restoreOpts := &runconfig.RestoreConfig{
36+
CriuOpts: runconfig.CriuConfig{
37+
ImagesDirectory: *flImgDir,
38+
WorkDirectory: *flWorkDir,
39+
TCPEstablished: true,
40+
ExternalUnixConnections: true,
41+
FileLocks: true,
42+
},
43+
ForceRestore: *flForce,
44+
}
45+
46+
var encounteredError error
47+
for _, name := range cmd.Args() {
48+
_, _, err := readBody(cli.call("POST", "/containers/"+name+"/restore", restoreOpts, nil))
49+
if err != nil {
50+
fmt.Fprintf(cli.err, "%s\n", err)
51+
encounteredError = fmt.Errorf("Error: failed to restore one or more containers")
52+
} else {
53+
fmt.Fprintf(cli.out, "%s\n", name)
54+
}
55+
}
56+
return encounteredError
57+
}

api/server/router/local/local.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ func (r *router) initRoutes() {
148148
NewDeleteRoute("/images/{name:.*}", r.deleteImages),
149149
NewDeleteRoute("/volumes/{name:.*}", r.deleteVolumes),
150150
}
151+
152+
addExperimentalRoutes(r)
151153
}
152154

153155
func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// +build experimental
2+
3+
package local
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
"net/http"
9+
10+
"github.com/docker/docker/api/server/httputils"
11+
dkrouter "github.com/docker/docker/api/server/router"
12+
"github.com/docker/docker/runconfig"
13+
"golang.org/x/net/context"
14+
)
15+
16+
func addExperimentalRoutes(r *router) {
17+
newRoutes := []dkrouter.Route{
18+
NewPostRoute("/containers/{name:.*}/checkpoint", r.postContainersCheckpoint),
19+
NewPostRoute("/containers/{name:.*}/restore", r.postContainersRestore),
20+
}
21+
22+
r.routes = append(r.routes, newRoutes...)
23+
}
24+
25+
func (s *router) postContainersCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
26+
if vars == nil {
27+
return fmt.Errorf("Missing parameter")
28+
}
29+
if err := httputils.CheckForJSON(r); err != nil {
30+
return err
31+
}
32+
33+
criuOpts := &runconfig.CriuConfig{}
34+
if err := json.NewDecoder(r.Body).Decode(criuOpts); err != nil {
35+
return err
36+
}
37+
38+
if err := s.daemon.ContainerCheckpoint(vars["name"], criuOpts); err != nil {
39+
return err
40+
}
41+
42+
w.WriteHeader(http.StatusNoContent)
43+
return nil
44+
}
45+
46+
func (s *router) postContainersRestore(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
47+
if vars == nil {
48+
return fmt.Errorf("Missing parameter")
49+
}
50+
if err := httputils.CheckForJSON(r); err != nil {
51+
return err
52+
}
53+
54+
restoreOpts := runconfig.RestoreConfig{}
55+
if err := json.NewDecoder(r.Body).Decode(&restoreOpts); err != nil {
56+
return err
57+
}
58+
59+
if err := s.daemon.ContainerRestore(vars["name"], &restoreOpts.CriuOpts, restoreOpts.ForceRestore); err != nil {
60+
return err
61+
}
62+
63+
w.WriteHeader(http.StatusNoContent)
64+
return nil
65+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// +build !experimental
2+
3+
package local
4+
5+
func addExperimentalRoutes(r *router) {
6+
}

api/server/server.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -115,36 +115,6 @@ func (s *HTTPServer) Close() error {
115115
return s.l.Close()
116116
}
117117

118-
func postContainersCheckpoint(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
119-
if vars == nil {
120-
return fmt.Errorf("Missing parameter")
121-
}
122-
if err := parseForm(r); err != nil {
123-
return err
124-
}
125-
job := eng.Job("checkpoint", vars["name"])
126-
if err := job.Run(); err != nil {
127-
return err
128-
}
129-
w.WriteHeader(http.StatusNoContent)
130-
return nil
131-
}
132-
133-
func postContainersRestore(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
134-
if vars == nil {
135-
return fmt.Errorf("Missing parameter")
136-
}
137-
if err := parseForm(r); err != nil {
138-
return err
139-
}
140-
job := eng.Job("restore", vars["name"])
141-
if err := job.Run(); err != nil {
142-
return err
143-
}
144-
w.WriteHeader(http.StatusNoContent)
145-
return nil
146-
}
147-
148118
func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
149119
logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
150120
w.Header().Add("Access-Control-Allow-Origin", corsHeaders)

api/types/types.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,19 @@ type ExecStartCheck struct {
231231
// ContainerState stores container's running state
232232
// it's part of ContainerJSONBase and will return by "inspect" command
233233
type ContainerState struct {
234-
Status string
235-
Running bool
236-
Paused bool
237-
Restarting bool
238-
OOMKilled bool
239-
Dead bool
240-
Pid int
241-
ExitCode int
242-
Error string
243-
StartedAt string
244-
FinishedAt string
234+
Status string
235+
Running bool
236+
Paused bool
237+
Checkpointed bool
238+
Restarting bool
239+
OOMKilled bool
240+
Dead bool
241+
Pid int
242+
ExitCode int
243+
Error string
244+
StartedAt string
245+
FinishedAt string
246+
CheckpointedAt string `json:"-"`
245247
}
246248

247249
// ContainerJSONBase contains response of Remote API:

0 commit comments

Comments
 (0)