Compare commits

..

2 Commits

Author SHA1 Message Date
Jessica Frazelle 395ccedc9b fix release script
Signed-off-by: Jessica Frazelle <princess@docker.com>
2015-05-27 20:11:24 -07:00
Jessica Frazelle 22a6d71919 Bump version to v1.7.0
Signed-off-by: Jessica Frazelle <princess@docker.com>
2015-05-27 19:17:33 -07:00
217 changed files with 1763 additions and 4409 deletions
-3
View File
@@ -30,8 +30,5 @@ docs/_build
docs/_static
docs/_templates
docs/changed-files
# generated by man/man/md2man-all.sh
man/man1
man/man5
pyenv
vendor/pkg/
+1 -1
View File
@@ -17,7 +17,7 @@
#### Quality
* Networking stack was entirely rewritten as part of the libnetwork effort
* Engine internals refactoring
* Engine internals refactoring (shout out to the contributors?)
* Volumes code was entirely rewritten to support the plugins effort
+ Sending SIGUSR1 to a daemon will dump all goroutines stacks without exiting
+4 -4
View File
@@ -30,7 +30,7 @@ security@docker.com and not by creating a github issue.
A common method for distributing applications and sandboxing their
execution is to use virtual machines, or VMs. Typical VM formats are
VMware's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory
VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory
these formats should allow every developer to automatically package
their application into a "machine" for easy distribution and deployment.
In practice, that almost never happens, for a few reasons:
@@ -180,7 +180,7 @@ Contributing to Docker
======================
[![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker)
[![Jenkins Build Status](https://jenkins.dockerproject.org/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/job/Docker%20Master/)
[![Jenkins Build Status](https://jenkins.dockerproject.com/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.com/job/Docker%20Master/)
Want to hack on Docker? Awesome! We have [instructions to help you get
started contributing code or documentation.](https://docs.docker.com/project/who-written-for/).
@@ -192,12 +192,12 @@ Getting the development builds
==============================
Want to run Docker from a master build? You can download
master builds at [master.dockerproject.org](https://master.dockerproject.org).
master builds at [master.dockerproject.com](https://master.dockerproject.com).
They are updated with each commit merged into the master branch.
Don't know how to use that super cool new feature in the master build? Check
out the master docs at
[docs.master.dockerproject.org](http://docs.master.dockerproject.org).
[docs.master.dockerproject.com](http://docs.master.dockerproject.com).
How the project is run
======================
+1 -1
View File
@@ -1 +1 @@
1.7.0-rc3
1.7.0-rc1
+9 -9
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"reflect"
"strings"
@@ -96,7 +97,7 @@ func (cli *DockerCli) Cmd(args ...string) error {
if len(args) > 0 {
method, exists := cli.getMethod(args[0])
if !exists {
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
return fmt.Errorf("docker: '%s' is not a docker command. See 'docker --help'.", args[0])
}
return method(args[1:]...)
}
@@ -116,19 +117,18 @@ func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bo
errorHandling = flag.ContinueOnError
}
flags := flag.NewFlagSet(name, errorHandling)
if signature != "" {
signature = " " + signature
}
flags.Usage = func() {
flags.ShortUsage()
flags.PrintDefaults()
}
flags.ShortUsage = func() {
options := ""
if signature != "" {
signature = " " + signature
}
if flags.FlagCountUndeprecated() > 0 {
options = " [OPTIONS]"
}
fmt.Fprintf(flags.Out(), "\nUsage: docker %s%s%s\n\n%s\n", name, options, signature, description)
fmt.Fprintf(cli.out, "\nUsage: docker %s%s%s\n\n%s\n\n", name, options, signature, description)
flags.SetOutput(cli.out)
flags.PrintDefaults()
os.Exit(0)
}
return flags
}
-1
View File
@@ -145,7 +145,6 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
if err != nil {
cmd.ReportError(err.Error(), true)
os.Exit(1)
}
if config.Image == "" {
cmd.Usage()
+17 -12
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/ioutils"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/units"
)
@@ -16,7 +15,7 @@ import (
func (cli *DockerCli) CmdInfo(args ...string) error {
cmd := cli.Subcmd("info", "", "Display system-wide information", true)
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
cmd.ParseFlags(args, false)
rdr, _, err := cli.call("GET", "/info", nil, nil)
if err != nil {
@@ -30,20 +29,20 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
fmt.Fprintf(cli.out, "Storage Driver: %s\n", info.Driver)
if info.DriverStatus != nil {
for _, pair := range info.DriverStatus {
fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
}
}
ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
fmt.Fprintf(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
fmt.Fprintf(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
fmt.Fprintf(cli.out, "Kernel Version: %s\n", info.KernelVersion)
fmt.Fprintf(cli.out, "Operating System: %s\n", info.OperatingSystem)
fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)
fmt.Fprintf(cli.out, "Name: %s\n", info.Name)
fmt.Fprintf(cli.out, "ID: %s\n", info.ID)
if info.Debug {
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
@@ -56,9 +55,15 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
}
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
if info.HttpProxy != "" {
fmt.Fprintf(cli.out, "Http Proxy: %s\n", info.HttpProxy)
}
if info.HttpsProxy != "" {
fmt.Fprintf(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
}
if info.NoProxy != "" {
fmt.Fprintf(cli.out, "No Proxy: %s\n", info.NoProxy)
}
if info.IndexServerAddress != "" {
u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
+1 -1
View File
@@ -16,7 +16,7 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
cmd.Require(flag.Max, 1)
cmd.ParseFlags(args, true)
cmd.ParseFlags(args, false)
serverAddress := registry.IndexServerAddress()
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
+1 -1
View File
@@ -12,7 +12,7 @@ import (
func (cli *DockerCli) CmdPause(args ...string) error {
cmd := cli.Subcmd("pause", "CONTAINER [CONTAINER...]", "Pause all processes within a container", true)
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
cmd.ParseFlags(args, false)
var errNames []string
for _, name := range cmd.Args() {
-1
View File
@@ -57,7 +57,6 @@ func (cli *DockerCli) CmdRun(args ...string) error {
// just in case the Parse does not exit
if err != nil {
cmd.ReportError(err.Error(), true)
os.Exit(1)
}
if len(hostConfig.Dns) > 0 {
+8 -4
View File
@@ -46,6 +46,7 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
var (
previousCPU uint64
previousSystem uint64
start = true
dec = json.NewDecoder(stream)
u = make(chan error, 1)
)
@@ -60,9 +61,10 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
cpuPercent = 0.0
)
previousCPU = v.PreCpuStats.CpuUsage.TotalUsage
previousSystem = v.PreCpuStats.SystemUsage
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
if !start {
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
}
start = false
s.mu.Lock()
s.CPUPercentage = cpuPercent
s.Memory = float64(v.MemoryStats.Usage)
@@ -71,6 +73,8 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
s.NetworkRx = float64(v.Network.RxBytes)
s.NetworkTx = float64(v.Network.TxBytes)
s.mu.Unlock()
previousCPU = v.CpuStats.CpuUsage.TotalUsage
previousSystem = v.CpuStats.SystemUsage
u <- nil
if !streamStats {
return
@@ -147,7 +151,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
}
// do a quick pause so that any failed connections for containers that do not exist are able to be
// evicted before we display the initial or default values.
time.Sleep(1500 * time.Millisecond)
time.Sleep(500 * time.Millisecond)
var errs []string
for _, c := range cStats {
c.mu.Lock()
+1 -1
View File
@@ -12,7 +12,7 @@ import (
func (cli *DockerCli) CmdUnpause(args ...string) error {
cmd := cli.Subcmd("unpause", "CONTAINER [CONTAINER...]", "Unpause all processes within a container", true)
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
cmd.ParseFlags(args, false)
var errNames []string
for _, name := range cmd.Args() {
+2 -8
View File
@@ -9,7 +9,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/autogen/dockerversion"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/utils"
)
// CmdVersion shows Docker version information.
@@ -21,7 +20,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
cmd.ParseFlags(args, false)
if dockerversion.VERSION != "" {
fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
@@ -32,9 +31,6 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
}
fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
if utils.ExperimentalBuild() {
fmt.Fprintf(cli.out, "Experimental (client): true\n")
}
stream, _, err := cli.call("GET", "/version", nil, nil)
if err != nil {
@@ -54,8 +50,6 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
fmt.Fprintf(cli.out, "Go version (server): %s\n", v.GoVersion)
fmt.Fprintf(cli.out, "Git commit (server): %s\n", v.GitCommit)
fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", v.Os, v.Arch)
if v.Experimental {
fmt.Fprintf(cli.out, "Experimental (server): true\n")
}
return nil
}
-9
View File
@@ -11,15 +11,6 @@ func boolValue(r *http.Request, k string) bool {
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
}
// boolValueOrDefault returns the default bool passed if the query param is
// missing, otherwise it's just a proxy to boolValue above
func boolValueOrDefault(r *http.Request, k string, d bool) bool {
if _, ok := r.Form[k]; !ok {
return d
}
return boolValue(r, k)
}
func int64ValueOrZero(r *http.Request, k string) int64 {
val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
if err != nil {
-15
View File
@@ -33,21 +33,6 @@ func TestBoolValue(t *testing.T) {
}
}
func TestBoolValueOrDefault(t *testing.T) {
r, _ := http.NewRequest("GET", "", nil)
if !boolValueOrDefault(r, "queryparam", true) {
t.Fatal("Expected to get true default value, got false")
}
v := url.Values{}
v.Set("param", "")
r, _ = http.NewRequest("GET", "", nil)
r.Form = v
if boolValueOrDefault(r, "param", true) {
t.Fatal("Expected not to get true")
}
}
func TestInt64ValueOrZero(t *testing.T) {
cases := map[string]int64{
"": 0,
+44 -55
View File
@@ -36,6 +36,7 @@ import (
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
"github.com/docker/libnetwork/portallocator"
)
type ServerConfig struct {
@@ -96,17 +97,15 @@ func (s *Server) ServeApi(protoAddrs []string) error {
if err != nil {
return err
}
s.servers = append(s.servers, srv...)
s.servers = append(s.servers, srv)
for _, s := range srv {
logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
go func(s serverCloser) {
if err := s.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
err = nil
}
chErrors <- err
}(s)
}
go func(proto, addr string) {
logrus.Infof("Listening for HTTP on %s (%s)", proto, addr)
if err := srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
err = nil
}
chErrors <- err
}(protoAddrParts[0], protoAddrParts[1])
}
for i := 0; i < len(protoAddrs); i++ {
@@ -253,11 +252,6 @@ func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *h
Os: runtime.GOOS,
Arch: runtime.GOARCH,
}
if version.GreaterThanOrEqualTo("1.19") {
v.Experimental = utils.ExperimentalBuild()
}
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
v.KernelVersion = kernelVersion.String()
}
@@ -277,20 +271,14 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit
name := vars["name"]
// If we have a signal, look at it. Otherwise, do nothing
if sigStr := r.Form.Get("signal"); sigStr != "" {
if sigStr := vars["signal"]; sigStr != "" {
// Check if we passed the signal as a number:
// The largest legal signal is 31, so let's parse on 5 bits
sigN, err := strconv.ParseUint(sigStr, 10, 5)
sig, err := strconv.ParseUint(sigStr, 10, 5)
if err != nil {
// The signal is not a number, treat it as a string (either like
// "KILL" or like "SIGKILL")
syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
if !ok {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
sig = uint64(syscallSig)
} else {
sig = sigN
sig = uint64(signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")])
}
if sig == 0 {
@@ -398,7 +386,6 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
}
until = u
}
timer := time.NewTimer(0)
timer.Stop()
if until > 0 {
@@ -457,9 +444,6 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
}
current, l := es.Subscribe()
if since == -1 {
current = nil
}
defer es.Evict(l)
for _, ev := range current {
if ev.Time < since {
@@ -469,12 +453,6 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
return err
}
}
var closeNotify <-chan bool
if closeNotifier, ok := w.(http.CloseNotifier); ok {
closeNotify = closeNotifier.CloseNotify()
}
for {
select {
case ev := <-l:
@@ -487,9 +465,6 @@ func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *ht
}
case <-timer.C:
return nil
case <-closeNotify:
logrus.Debug("Client disconnected, stop sending events")
return nil
}
}
}
@@ -575,16 +550,7 @@ func (s *Server) getContainersStats(version version.Version, w http.ResponseWrit
return fmt.Errorf("Missing parameter")
}
stream := boolValueOrDefault(r, "stream", true)
var out io.Writer
if !stream {
w.Header().Set("Content-Type", "application/json")
out = w
} else {
out = ioutils.NewWriteFlusher(w)
}
return s.daemon.ContainerStats(vars["name"], stream, out)
return s.daemon.ContainerStats(vars["name"], boolValue(r, "stream"), ioutils.NewWriteFlusher(w))
}
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -668,6 +634,10 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h
return err
}
if c == nil {
c = &runconfig.Config{}
}
containerCommitConfig := &daemon.ContainerCommitConfig{
Pause: pause,
Repo: r.Form.Get("repo"),
@@ -1163,14 +1133,6 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
return fmt.Errorf("Missing parameter")
}
if version.LessThan("1.19") {
containerJSONRaw, err := s.daemon.ContainerInspectRaw(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, containerJSONRaw)
}
containerJSON, err := s.daemon.ContainerInspect(vars["name"])
if err != nil {
return err
@@ -1584,3 +1546,30 @@ func createRouter(s *Server) *mux.Router {
return r
}
func allocateDaemonPort(addr string) error {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return err
}
intPort, err := strconv.Atoi(port)
if err != nil {
return err
}
var hostIPs []net.IP
if parsedIP := net.ParseIP(host); parsedIP != nil {
hostIPs = append(hostIPs, parsedIP)
} else if hostIPs, err = net.LookupIP(host); err != nil {
return fmt.Errorf("failed to lookup %s address in host specification", host)
}
pa := portallocator.Get()
for _, hostIP := range hostIPs {
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
}
}
return nil
}
+29 -49
View File
@@ -6,56 +6,63 @@ import (
"fmt"
"net"
"net/http"
"strconv"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/sockets"
"github.com/docker/docker/pkg/systemd"
"github.com/docker/libnetwork/portallocator"
)
// newServer sets up the required serverClosers and does protocol specific checking.
func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
// newServer sets up the required serverCloser and does protocol specific checking.
func (s *Server) newServer(proto, addr string) (serverCloser, error) {
var (
err error
ls []net.Listener
l net.Listener
)
switch proto {
case "fd":
ls, err = systemd.ListenFD(addr)
ls, err := systemd.ListenFD(addr)
if err != nil {
return nil, err
}
chErrors := make(chan error, len(ls))
// We don't want to start serving on these sockets until the
// daemon is initialized and installed. Otherwise required handlers
// won't be ready.
<-s.start
// Since ListenFD will return one or more sockets we have
// to create a go func to spawn off multiple serves
for i := range ls {
listener := ls[i]
go func() {
httpSrv := http.Server{Handler: s.router}
chErrors <- httpSrv.Serve(listener)
}()
}
for i := 0; i < len(ls); i++ {
if err := <-chErrors; err != nil {
return nil, err
}
}
return nil, nil
case "tcp":
l, err := s.initTcpSocket(addr)
l, err = s.initTcpSocket(addr)
if err != nil {
return nil, err
}
ls = append(ls, l)
case "unix":
l, err := sockets.NewUnixSocket(addr, s.cfg.SocketGroup, s.start)
if err != nil {
if l, err = sockets.NewUnixSocket(addr, s.cfg.SocketGroup, s.start); err != nil {
return nil, err
}
ls = append(ls, l)
default:
return nil, fmt.Errorf("Invalid protocol format: %q", proto)
}
var res []serverCloser
for _, l := range ls {
res = append(res, &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
},
l,
})
}
return res, nil
return &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
},
l,
}, nil
}
func (s *Server) AcceptConnections(d *daemon.Daemon) {
@@ -69,30 +76,3 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) {
close(s.start)
}
}
func allocateDaemonPort(addr string) error {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return err
}
intPort, err := strconv.Atoi(port)
if err != nil {
return err
}
var hostIPs []net.IP
if parsedIP := net.ParseIP(host); parsedIP != nil {
hostIPs = append(hostIPs, parsedIP)
} else if hostIPs, err = net.LookupIP(host); err != nil {
return fmt.Errorf("failed to lookup %s address in host specification", host)
}
pa := portallocator.Get()
for _, hostIP := range hostIPs {
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
}
}
return nil
}
+1 -6
View File
@@ -11,7 +11,7 @@ import (
)
// NewServer sets up the required Server and does protocol specific checking.
func (s *Server) newServer(proto, addr string) (serverCloser, error) {
func (s *Server) newServer(proto, addr string) (Server, error) {
var (
err error
l net.Listener
@@ -22,7 +22,6 @@ func (s *Server) newServer(proto, addr string) (serverCloser, error) {
if err != nil {
return nil, err
}
default:
return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
}
@@ -44,7 +43,3 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) {
close(s.start)
}
}
func allocateDaemonPort(addr string) error {
return nil
}
-1
View File
@@ -81,7 +81,6 @@ type Network struct {
type Stats struct {
Read time.Time `json:"read"`
Network Network `json:"network,omitempty"`
PreCpuStats CpuStats `json:"precpu_stats,omitempty"`
CpuStats CpuStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
+14 -35
View File
@@ -94,23 +94,23 @@ type ImageInspect struct {
// GET "/containers/json"
type Port struct {
IP string `json:",omitempty"`
IP string
PrivatePort int
PublicPort int `json:",omitempty"`
PublicPort int
Type string
}
type Container struct {
ID string `json:"Id"`
Names []string
Image string
Command string
Created int
Ports []Port
SizeRw int `json:",omitempty"`
SizeRootFs int `json:",omitempty"`
Labels map[string]string
Status string
ID string `json:"Id"`
Names []string `json:",omitempty"`
Image string `json:",omitempty"`
Command string `json:",omitempty"`
Created int `json:",omitempty"`
Ports []Port `json:",omitempty"`
SizeRw int `json:",omitempty"`
SizeRootFs int `json:",omitempty"`
Labels map[string]string `json:",omitempty"`
Status string `json:",omitempty"`
}
// POST "/containers/"+containerID+"/copy"
@@ -132,7 +132,6 @@ type Version struct {
Os string
Arch string
KernelVersion string `json:",omitempty"`
Experimental bool `json:",omitempty"`
}
// GET "/info"
@@ -195,11 +194,12 @@ type ContainerState struct {
}
// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
type ContainerJSON struct {
Id string
Created time.Time
Path string
Args []string
Config *runconfig.Config
State *ContainerState
Image string
NetworkSettings *network.Settings
@@ -219,24 +219,3 @@ type ContainerJSONBase struct {
ExecIDs []string
HostConfig *runconfig.HostConfig
}
type ContainerJSON struct {
*ContainerJSONBase
Config *runconfig.Config
}
// backcompatibility struct along with ContainerConfig
type ContainerJSONRaw struct {
*ContainerJSONBase
Config *ContainerConfig
}
type ContainerConfig struct {
*runconfig.Config
// backward compatibility, they now live in HostConfig
Memory int64
MemorySwap int64
CpuShares int64
Cpuset string
}
-4
View File
@@ -221,10 +221,6 @@ func Commit(d *daemon.Daemon, name string, c *daemon.ContainerCommitConfig) (str
return "", err
}
if c.Config == nil {
c.Config = &runconfig.Config{}
}
newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
if err != nil {
return "", err
-15
View File
@@ -1,15 +0,0 @@
#
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/generate.sh"!
#
FROM fedora:22
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux
+7 -24
View File
@@ -212,12 +212,11 @@ _docker_docker() {
--selinux-enabled
--tls
--tlsverify
--userland-proxy=false
--version -v
"
case "$prev" in
--exec-root|--graph|-g)
--graph|-g)
_filedir -d
return
;;
@@ -268,25 +267,22 @@ _docker_attach() {
_docker_build() {
case "$prev" in
--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--memory|-m|--memory-swap)
--tag|-t)
__docker_image_repos_and_tags
return
;;
--file|-f)
_filedir
return
;;
--tag|-t)
__docker_image_repos_and_tags
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--cgroup-parent --cpuset-cpus --cpuset-mems --cpu-shares -c --cpu-period --cpu-quota --file -f --force-rm --help --memory -m --memory-swap --no-cache --pull --quiet -q --rm --tag -t" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--cpu-shares -c --cpuset-cpus --cpu-quota --file -f --force-rm --help --memory -m --memory-swap --no-cache --pull --quiet -q --rm --tag -t" -- "$cur" ) )
;;
*)
local counter="$(__docker_pos_first_nonflag '--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--file|-f|--memory|-m|--memory-swap|--tag|-t')"
local counter="$(__docker_pos_first_nonflag '--tag|-t')"
if [ $cword -eq $counter ]; then
_filedir -d
fi
@@ -409,12 +405,6 @@ _docker_events() {
}
_docker_exec() {
case "$prev" in
--user|-u)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) )
@@ -596,7 +586,7 @@ _docker_logout() {
_docker_logs() {
case "$prev" in
--since|--tail)
--tail)
return
;;
esac
@@ -781,16 +771,15 @@ _docker_rmi() {
_docker_run() {
local options_with_args="
--add-host
--blkio-weight
--attach -a
--cap-add
--cap-drop
--cgroup-parent
--cidfile
--cpuset
--cpu-shares -c
--cpu-period
--cpu-quota
--cpu-shares -c
--device
--dns
--dns-search
@@ -816,7 +805,6 @@ _docker_run() {
--security-opt
--user -u
--ulimit
--uts
--volumes-from
--volume -v
--workdir -w
@@ -1168,8 +1156,6 @@ _docker() {
--api-cors-header
--bip
--bridge -b
--default-gateway
--default-gateway-v6
--default-ulimit
--dns
--dns-search
@@ -1217,9 +1203,6 @@ _docker() {
;;
-*)
;;
=)
(( counter++ ))
;;
*)
command="${words[$counter]}"
cpos=$counter
+1 -1
View File
@@ -1,6 +1,6 @@
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
Documentation=http://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
+1 -1
View File
@@ -80,7 +80,7 @@ sudo mkdir -m 755 dev
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
# locales
sudo rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
# docs and man pages
# docs
sudo rm -rf usr/share/{man,doc,info,gnome/help}
# cracklib
sudo rm -rf usr/share/cracklib
+1 -1
View File
@@ -10,7 +10,7 @@ shift
# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target"
# locales
rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
# docs and man pages
# docs
rm -rf usr/share/{man,doc,info,gnome/help}
# cracklib
rm -rf usr/share/cracklib
+38 -5
View File
@@ -1,6 +1,8 @@
package daemon
import (
"net"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/runconfig"
@@ -14,7 +16,9 @@ const (
// CommonConfig defines the configuration of a docker daemon which are
// common across platforms.
type CommonConfig struct {
AutoRestart bool
AutoRestart bool
// Bridge holds bridge network specific configuration.
Bridge bridgeConfig
Context map[string][]string
CorsHeaders string
DisableNetwork bool
@@ -22,10 +26,8 @@ type CommonConfig struct {
DnsSearch []string
EnableCors bool
ExecDriver string
ExecOptions []string
ExecRoot string
GraphDriver string
GraphOptions []string
Labels []string
LogConfig runconfig.LogConfig
Mtu int
@@ -34,26 +36,57 @@ type CommonConfig struct {
TrustKeyPath string
}
// bridgeConfig stores all the bridge driver specific
// configuration.
type bridgeConfig struct {
EnableIPv6 bool
EnableIPTables bool
EnableIPForward bool
EnableIPMasq bool
EnableUserlandProxy bool
DefaultIP net.IP
Iface string
IP string
FixedCIDR string
FixedCIDRv6 string
DefaultGatewayIPv4 string
DefaultGatewayIPv6 string
InterContainerCommunication bool
}
// InstallCommonFlags adds command-line options to the top-level flag parser for
// the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed
// from the command-line.
func (config *Config) InstallCommonFlags() {
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, defaultPidFile, "Path to use for daemon PID file")
flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
flag.StringVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
flag.StringVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, "Exec driver to use")
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
// FIXME: why the inconsistency between "hosts" and "sockets"?
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
opts.LabelListVar(&config.Labels, []string{"-label"}, "Set key=value labels to the daemon")
flag.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", "Default driver for container logs")
opts.LogOptsVar(config.LogConfig.Config, []string{"-log-opt"}, "Set log driver options")
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
}
+4 -36
View File
@@ -1,8 +1,6 @@
package daemon
import (
"net"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/ulimit"
@@ -21,32 +19,13 @@ type Config struct {
CommonConfig
// Fields below here are platform specific.
// Bridge holds bridge network specific configuration.
Bridge bridgeConfig
EnableSelinuxSupport bool
ExecOptions []string
GraphOptions []string
SocketGroup string
Ulimits map[string]*ulimit.Ulimit
}
// bridgeConfig stores all the bridge driver specific
// configuration.
type bridgeConfig struct {
EnableIPv6 bool
EnableIPTables bool
EnableIPForward bool
EnableIPMasq bool
EnableUserlandProxy bool
DefaultIP net.IP
Iface string
IP string
FixedCIDR string
FixedCIDRv6 string
DefaultGatewayIPv4 net.IP
DefaultGatewayIPv6 net.IP
InterContainerCommunication bool
}
// InstallFlags adds command-line options to the top-level flag parser for
// the current process.
// Subsequent calls to `flag.Parse` will populate config with values parsed
@@ -56,21 +35,10 @@ func (config *Config) InstallFlags() {
config.InstallCommonFlags()
// Then platform-specific install flags
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
opts.ListVar(&config.ExecOptions, []string{"-exec-opt"}, "Set exec driver options")
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
config.Ulimits = make(map[string]*ulimit.Ulimit)
opts.UlimitMapVar(config.Ulimits, []string{"-default-ulimit"}, "Set default ulimits for containers")
flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
opts.IPVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
opts.IPVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
}
+1 -13
View File
@@ -73,10 +73,7 @@ type CommonContainer struct {
MountLabel, ProcessLabel string
RestartCount int
UpdateDns bool
MountPoints map[string]*mountPoint
Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility
VolumesRW map[string]bool // Deprecated since 1.7, kept for backwards compatibility
MountPoints map[string]*mountPoint
hostConfig *runconfig.HostConfig
command *execdriver.Command
@@ -1057,15 +1054,6 @@ func (container *Container) networkMounts() []execdriver.Mount {
return mounts
}
func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
container.MountPoints[destination] = &mountPoint{
Name: name,
Source: source,
Destination: destination,
RW: rw,
}
}
func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
container.MountPoints[destination] = &mountPoint{
Name: name,
+4 -40
View File
@@ -183,7 +183,7 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.
func populateCommand(c *Container, env []string) error {
var en *execdriver.Network
if !c.Config.NetworkDisabled {
if !c.daemon.config.DisableNetwork {
en = &execdriver.Network{
NamespacePath: c.NetworkSettings.SandboxKey,
}
@@ -227,10 +227,9 @@ func populateCommand(c *Container, env []string) error {
userSpecifiedDevices = append(userSpecifiedDevices, devs...)
}
allowedDevices := append(configs.DefaultAllowedDevices, userSpecifiedDevices...)
allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices)
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
autoCreatedDevices := append(configs.DefaultAutoCreatedDevices, userSpecifiedDevices...)
// TODO: this can be removed after lxc-conf is fully deprecated
lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
@@ -310,25 +309,6 @@ func populateCommand(c *Container, env []string) error {
return nil
}
func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device {
if len(userDevices) == 0 {
return defaultDevices
}
paths := map[string]*configs.Device{}
for _, d := range userDevices {
paths[d.Path] = d
}
var devs []*configs.Device
for _, d := range defaultDevices {
if _, defined := paths[d.Path]; !defined {
devs = append(devs, d)
}
}
return append(devs, userDevices...)
}
// GetSize, return real size, virtual size
func (container *Container) GetSize() (int64, int64) {
var (
@@ -513,23 +493,13 @@ func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork
networkSettings.MacAddress = mac.(net.HardwareAddr).String()
}
networkSettings.Ports = nat.PortMap{}
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
if exposedPorts, ok := expData.([]types.TransportPort); ok {
for _, tp := range exposedPorts {
natPort := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
networkSettings.Ports[natPort] = nil
}
}
}
mapData, ok := driverInfo[netlabel.PortMap]
if !ok {
return networkSettings, nil
}
if portMapping, ok := mapData.([]types.PortBinding); ok {
networkSettings.Ports = nat.PortMap{}
for _, pp := range portMapping {
natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
@@ -943,12 +913,6 @@ func (container *Container) ReleaseNetwork() {
return
}
// If the container is not attached to any network do not try
// to release network and generate spurious error messages.
if container.NetworkSettings.NetworkID == "" {
return
}
n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
if err != nil {
logrus.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
-4
View File
@@ -15,10 +15,6 @@ import (
)
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig) (string, []string, error) {
if config == nil {
return "", nil, fmt.Errorf("Config cannot be empty in order to create a container")
}
warnings, err := daemon.verifyHostConfig(hostConfig)
if err != nil {
return "", warnings, err
+39 -56
View File
@@ -50,6 +50,8 @@ import (
"github.com/docker/docker/volume/local"
)
const defaultVolumesPathName = "volumes"
var (
validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
@@ -156,7 +158,12 @@ func (daemon *Daemon) containerRoot(id string) string {
// This is typically done at startup.
func (daemon *Daemon) load(id string) (*Container, error) {
container := &Container{
CommonContainer: daemon.newBaseContainer(id),
CommonContainer: CommonContainer{
State: NewState(),
root: daemon.containerRoot(id),
MountPoints: make(map[string]*mountPoint),
execCommands: newExecStore(),
},
}
if err := container.FromDisk(); err != nil {
@@ -206,7 +213,7 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err
// we'll waste time if we update it for every container
daemon.idIndex.Add(container.ID)
if err := daemon.verifyVolumesInfo(container); err != nil {
if err := daemon.verifyOldVolumesInfo(container); err != nil {
return err
}
@@ -519,21 +526,25 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
daemon.generateHostname(id, config)
entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)
base := daemon.newBaseContainer(id)
base.Created = time.Now().UTC()
base.Path = entrypoint
base.Args = args //FIXME: de-duplicate from config
base.Config = config
base.hostConfig = &runconfig.HostConfig{}
base.ImageID = imgID
base.NetworkSettings = &network.Settings{}
base.Name = name
base.Driver = daemon.driver.String()
base.ExecDriver = daemon.execDriver.Name()
container := &Container{
CommonContainer: base,
CommonContainer: CommonContainer{
ID: id, // FIXME: we should generate the ID here instead of receiving it as an argument
Created: time.Now().UTC(),
Path: entrypoint,
Args: args, //FIXME: de-duplicate from config
Config: config,
hostConfig: &runconfig.HostConfig{},
ImageID: imgID,
NetworkSettings: &network.Settings{},
Name: name,
Driver: daemon.driver.String(),
ExecDriver: daemon.execDriver.Name(),
State: NewState(),
execCommands: newExecStore(),
MountPoints: map[string]*mountPoint{},
},
}
container.root = daemon.containerRoot(container.ID)
return container, err
}
@@ -781,7 +792,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
return nil, err
}
volumesDriver, err := local.New(config.Root)
volumesDriver, err := local.New(filepath.Join(config.Root, defaultVolumesPathName))
if err != nil {
return nil, err
}
@@ -952,14 +963,6 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
netOption["FixedCIDRv6"] = fCIDRv6
}
if config.Bridge.DefaultGatewayIPv4 != nil {
netOption["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4
}
if config.Bridge.DefaultGatewayIPv6 != nil {
netOption["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6
}
// --ip processing
if config.Bridge.DefaultIP != nil {
netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
@@ -979,6 +982,16 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
}
func (daemon *Daemon) Shutdown() error {
if daemon.containerGraph != nil {
if err := daemon.containerGraph.Close(); err != nil {
logrus.Errorf("Error during container graph.Close(): %v", err)
}
}
if daemon.driver != nil {
if err := daemon.driver.Cleanup(); err != nil {
logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
}
}
if daemon.containers != nil {
group := sync.WaitGroup{}
logrus.Debug("starting clean shutdown of all containers...")
@@ -990,9 +1003,8 @@ func (daemon *Daemon) Shutdown() error {
go func() {
defer group.Done()
// If container failed to exit in 10 seconds of SIGTERM, then using the force
if err := c.Stop(10); err != nil {
logrus.Errorf("Stop container %s with error: %v", c.ID, err)
if err := c.KillSig(15); err != nil {
logrus.Debugf("kill 15 error for %s - %s", c.ID, err)
}
c.WaitStop(-1 * time.Second)
logrus.Debugf("container stopped %s", c.ID)
@@ -1000,23 +1012,6 @@ func (daemon *Daemon) Shutdown() error {
}
}
group.Wait()
// trigger libnetwork GC only if it's initialized
if daemon.netController != nil {
daemon.netController.GC()
}
}
if daemon.containerGraph != nil {
if err := daemon.containerGraph.Close(); err != nil {
logrus.Errorf("Error during container graph.Close(): %v", err)
}
}
if daemon.driver != nil {
if err := daemon.driver.Cleanup(); err != nil {
logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
}
}
return nil
@@ -1250,15 +1245,3 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
container.toDisk()
return nil
}
func (daemon *Daemon) newBaseContainer(id string) CommonContainer {
return CommonContainer{
ID: id,
State: NewState(),
MountPoints: make(map[string]*mountPoint),
Volumes: make(map[string]string),
VolumesRW: make(map[string]bool),
execCommands: newExecStore(),
root: daemon.containerRoot(id),
}
}
+30 -339
View File
@@ -12,8 +12,6 @@ import (
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
"github.com/docker/docker/volume/local"
)
//
@@ -129,311 +127,14 @@ func TestLoadWithVolume(t *testing.T) {
}
defer os.RemoveAll(tmp)
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
containerPath := filepath.Join(tmp, containerId)
if err := os.MkdirAll(containerPath, 0755); err != nil {
t.Fatal(err)
}
hostVolumeId := stringid.GenerateRandomID()
vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
if err := os.MkdirAll(vfsPath, 0755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(volumePath, 0755); err != nil {
t.Fatal(err)
}
content := filepath.Join(vfsPath, "helo")
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
t.Fatal(err)
}
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
cfg := fmt.Sprintf(config, vfsPath)
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil {
t.Fatal(err)
}
hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
t.Fatal(err)
}
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
defer volumedrivers.Unregister(volume.DefaultDriverName)
c, err := daemon.load(containerId)
if err != nil {
t.Fatal(err)
}
err = daemon.verifyVolumesInfo(c)
if err != nil {
t.Fatal(err)
}
if len(c.MountPoints) != 1 {
t.Fatalf("Expected 1 volume mounted, was 0\n")
}
m := c.MountPoints["/vol1"]
if m.Name != hostVolumeId {
t.Fatalf("Expected mount name to be %s, was %s\n", hostVolumeId, m.Name)
}
if m.Destination != "/vol1" {
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
}
if !m.RW {
t.Fatalf("Expected mount point to be RW but it was not\n")
}
if m.Driver != volume.DefaultDriverName {
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
}
newVolumeContent := filepath.Join(volumePath, local.VolumeDataPathName, "helo")
b, err := ioutil.ReadFile(newVolumeContent)
if err != nil {
t.Fatal(err)
}
if string(b) != "HELO" {
t.Fatalf("Expected HELO, was %s\n", string(b))
}
}
func TestLoadWithBindMount(t *testing.T) {
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
containerPath := filepath.Join(tmp, containerId)
if err = os.MkdirAll(containerPath, 0755); err != nil {
t.Fatal(err)
}
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
"UpdateDns":false,"Volumes":{"/vol1": "/vol1"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
t.Fatal(err)
}
hostConfig := `{"Binds":["/vol1:/vol1"],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
t.Fatal(err)
}
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
defer volumedrivers.Unregister(volume.DefaultDriverName)
c, err := daemon.load(containerId)
if err != nil {
t.Fatal(err)
}
err = daemon.verifyVolumesInfo(c)
if err != nil {
t.Fatal(err)
}
if len(c.MountPoints) != 1 {
t.Fatalf("Expected 1 volume mounted, was 0\n")
}
m := c.MountPoints["/vol1"]
if m.Name != "" {
t.Fatalf("Expected empty mount name, was %s\n", m.Name)
}
if m.Source != "/vol1" {
t.Fatalf("Expected mount source /vol1, was %s\n", m.Source)
}
if m.Destination != "/vol1" {
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
}
if !m.RW {
t.Fatalf("Expected mount point to be RW but it was not\n")
}
}
func TestLoadWithVolume17RC(t *testing.T) {
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
containerPath := filepath.Join(tmp, containerId)
if err := os.MkdirAll(containerPath, 0755); err != nil {
t.Fatal(err)
}
hostVolumeId := "6a3c03fc4a4e588561a543cc3bdd50089e27bd11bbb0e551e19bf735e2514101"
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
if err := os.MkdirAll(volumePath, 0755); err != nil {
t.Fatal(err)
}
content := filepath.Join(volumePath, "helo")
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
t.Fatal(err)
}
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","PortMapping":null,"Ports":{}},
"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
"UpdateDns":false,"MountPoints":{"/vol1":{"Name":"6a3c03fc4a4e588561a543cc3bdd50089e27bd11bbb0e551e19bf735e2514101","Destination":"/vol1","Driver":"local","RW":true,"Source":"","Relabel":""}},"AppliedVolumesFrom":null}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
t.Fatal(err)
}
hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
t.Fatal(err)
}
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
defer volumedrivers.Unregister(volume.DefaultDriverName)
c, err := daemon.load(containerId)
if err != nil {
t.Fatal(err)
}
err = daemon.verifyVolumesInfo(c)
if err != nil {
t.Fatal(err)
}
if len(c.MountPoints) != 1 {
t.Fatalf("Expected 1 volume mounted, was 0\n")
}
m := c.MountPoints["/vol1"]
if m.Name != hostVolumeId {
t.Fatalf("Expected mount name to be %s, was %s\n", hostVolumeId, m.Name)
}
if m.Destination != "/vol1" {
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
}
if !m.RW {
t.Fatalf("Expected mount point to be RW but it was not\n")
}
if m.Driver != volume.DefaultDriverName {
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
}
newVolumeContent := filepath.Join(volumePath, local.VolumeDataPathName, "helo")
b, err := ioutil.ReadFile(newVolumeContent)
if err != nil {
t.Fatal(err)
}
if string(b) != "HELO" {
t.Fatalf("Expected HELO, was %s\n", string(b))
}
}
func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
tmp, err := ioutil.TempDir("", "docker-daemon-test-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
containerPath := filepath.Join(tmp, containerId)
if err := os.MkdirAll(containerPath, 0755); err != nil {
t.Fatal(err)
}
hostVolumeId := stringid.GenerateRandomID()
vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
volumePath := filepath.Join(tmp, "volumes", hostVolumeId)
if err := os.MkdirAll(vfsPath, 0755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(volumePath, 0755); err != nil {
t.Fatal(err)
}
content := filepath.Join(vfsPath, "helo")
if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil {
t.Fatal(err)
}
volumePath := filepath.Join(tmp, "vfs", "dir", hostVolumeId)
config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
@@ -451,7 +152,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
cfg := fmt.Sprintf(config, vfsPath)
cfg := fmt.Sprintf(config, volumePath)
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil {
t.Fatal(err)
}
@@ -464,53 +165,43 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
t.Fatal(err)
}
daemon, err := initDaemonForVolumesTest(tmp)
if err != nil {
t.Fatal(err)
}
defer volumedrivers.Unregister(volume.DefaultDriverName)
c, err := daemon.load(containerId)
if err != nil {
if err = os.MkdirAll(volumePath, 0755); err != nil {
t.Fatal(err)
}
err = daemon.verifyVolumesInfo(c)
if err != nil {
t.Fatal(err)
}
if len(c.MountPoints) != 1 {
t.Fatalf("Expected 1 volume mounted, was 0\n")
}
m := c.MountPoints["/vol1"]
v, err := createVolume(m.Name, m.Driver)
if err != nil {
t.Fatal(err)
}
if err := removeVolume(v); err != nil {
t.Fatal(err)
}
fi, err := os.Stat(vfsPath)
if err == nil || !os.IsNotExist(err) {
t.Fatalf("Expected vfs path to not exist: %v - %v\n", fi, err)
}
}
func initDaemonForVolumesTest(tmp string) (*Daemon, error) {
daemon := &Daemon{
repository: tmp,
root: tmp,
}
volumesDriver, err := local.New(tmp)
c, err := daemon.load(containerId)
if err != nil {
return nil, err
t.Fatal(err)
}
volumedrivers.Register(volumesDriver, volumesDriver.Name())
return daemon, nil
err = daemon.verifyOldVolumesInfo(c)
if err != nil {
t.Fatal(err)
}
if len(c.MountPoints) != 1 {
t.Fatalf("Expected 1 volume mounted, was 0\n")
}
m := c.MountPoints["/vol1"]
if m.Name != hostVolumeId {
t.Fatalf("Expected mount name to be %s, was %s\n", hostVolumeId, m.Name)
}
if m.Destination != "/vol1" {
t.Fatalf("Expected mount destination /vol1, was %s\n", m.Destination)
}
if !m.RW {
t.Fatalf("Expected mount point to be RW but it was not\n")
}
if m.Driver != volume.DefaultDriverName {
t.Fatalf("Expected mount driver local, was %s\n", m.Driver)
}
}
-1
View File
@@ -24,7 +24,6 @@ func InitContainer(c *Command) *configs.Config {
container.Devices = c.AutoCreatedDevices
container.Rootfs = c.Rootfs
container.Readonlyfs = c.ReadonlyRootfs
container.Privatefs = true
// check to see if we are running in ramdisk to disable pivot root
container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
+1 -1
View File
@@ -124,7 +124,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
dataPath = d.containerDir(c.ID)
)
if c.Network == nil || (c.Network.NamespacePath == "" && c.Network.ContainerID == "") {
if c.Network.NamespacePath == "" && c.Network.ContainerID == "" {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
}
+2 -4
View File
@@ -17,7 +17,6 @@ import (
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/libcontainer/label"
zfs "github.com/mistifyio/go-zfs"
)
@@ -282,15 +281,14 @@ func (d *Driver) Remove(id string) error {
func (d *Driver) Get(id, mountLabel string) (string, error) {
mountpoint := d.MountPath(id)
filesystem := d.ZfsPath(id)
options := label.FormatMountLabel("", mountLabel)
log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options)
log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, mountLabel)
// Create the target directories if they don't exist
if err := os.MkdirAll(mountpoint, 0755); err != nil && !os.IsExist(err) {
return "", err
}
err := mount.Mount(filesystem, mountpoint, "zfs", options)
err := mount.Mount(filesystem, mountpoint, "zfs", mountLabel)
if err != nil {
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
}
+2 -3
View File
@@ -63,8 +63,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
repos := daemon.Repositories().ByID()[img.ID]
//If delete by id, see if the id belong only to one repository
deleteByID := repoName == ""
if deleteByID {
if repoName == "" {
for _, repoAndTag := range repos {
parsedRepo, parsedTag := parsers.ParseRepositoryTag(repoAndTag)
if repoName == "" || repoName == parsedRepo {
@@ -92,7 +91,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
return nil
}
if len(repos) <= 1 || (len(repoAndTags) <= 1 && deleteByID) {
if len(repos) <= 1 {
if err := daemon.canDeleteImage(img.ID, force); err != nil {
return err
}
+3 -36
View File
@@ -25,40 +25,6 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
container.Lock()
defer container.Unlock()
base, err := daemon.getInspectData(container)
if err != nil {
return nil, err
}
return &types.ContainerJSON{base, container.Config}, nil
}
func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw, error) {
container, err := daemon.Get(name)
if err != nil {
return nil, err
}
container.Lock()
defer container.Unlock()
base, err := daemon.getInspectData(container)
if err != nil {
return nil, err
}
config := &types.ContainerConfig{
container.Config,
container.hostConfig.Memory,
container.hostConfig.MemorySwap,
container.hostConfig.CpuShares,
container.hostConfig.CpusetCpus,
}
return &types.ContainerJSONRaw{base, config}, nil
}
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
// make a copy to play with
hostConfig := *container.hostConfig
@@ -94,11 +60,12 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
volumesRW[m.Destination] = m.RW
}
contJSONBase := &types.ContainerJSONBase{
contJSON := &types.ContainerJSON{
Id: container.ID,
Created: container.Created,
Path: container.Path,
Args: container.Args,
Config: container.Config,
State: containerState,
Image: container.ImageID,
NetworkSettings: container.NetworkSettings,
@@ -119,7 +86,7 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
HostConfig: &hostConfig,
}
return contJSONBase, nil
return contJSON, nil
}
func (daemon *Daemon) ContainerExecInspect(id string) (*execConfig, error) {
+7 -21
View File
@@ -2,7 +2,6 @@ package logger
import (
"bufio"
"bytes"
"io"
"sync"
"time"
@@ -41,27 +40,14 @@ func (c *Copier) Run() {
func (c *Copier) copySrc(name string, src io.Reader) {
defer c.copyJobs.Done()
reader := bufio.NewReader(src)
for {
line, err := reader.ReadBytes('\n')
line = bytes.TrimSuffix(line, []byte{'\n'})
// ReadBytes can return full or partial output even when it failed.
// e.g. it can return a full entry and EOF.
if err == nil || len(line) > 0 {
if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil {
logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr)
}
scanner := bufio.NewScanner(src)
for scanner.Scan() {
if err := c.dst.Log(&Message{ContainerID: c.cid, Line: scanner.Bytes(), Source: name, Timestamp: time.Now().UTC()}); err != nil {
logrus.Errorf("Failed to log msg %q for logger %s: %s", scanner.Bytes(), c.dst.Name(), err)
}
if err != nil {
if err != io.EOF {
logrus.Errorf("Error scanning log stream: %s", err)
}
return
}
}
if err := scanner.Err(); err != nil {
logrus.Errorf("Error scanning log stream: %s", err)
}
}
+2 -46
View File
@@ -3,17 +3,14 @@
package syslog
import (
"fmt"
"io"
"log/syslog"
"net"
"net/url"
"os"
"path"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/pkg/urlutil"
)
const name = "syslog"
@@ -30,18 +27,7 @@ func init() {
func New(ctx logger.Context) (logger.Logger, error) {
tag := ctx.ContainerID[:12]
proto, address, err := parseAddress(ctx.Config["syslog-address"])
if err != nil {
return nil, err
}
log, err := syslog.Dial(
proto,
address,
syslog.LOG_DAEMON,
path.Base(os.Args[0])+"/"+tag,
)
log, err := syslog.New(syslog.LOG_DAEMON, fmt.Sprintf("%s/%s", path.Base(os.Args[0]), tag))
if err != nil {
return nil, err
}
@@ -69,33 +55,3 @@ func (s *Syslog) Name() string {
func (s *Syslog) GetReader() (io.Reader, error) {
return nil, logger.ReadLogsNotSupported
}
func parseAddress(address string) (string, string, error) {
if urlutil.IsTransportURL(address) {
url, err := url.Parse(address)
if err != nil {
return "", "", err
}
// unix socket validation
if url.Scheme == "unix" {
if _, err := os.Stat(url.Path); err != nil {
return "", "", err
}
return url.Scheme, url.Path, nil
}
// here we process tcp|udp
host := url.Host
if _, _, err := net.SplitHostPort(host); err != nil {
if !strings.Contains(err.Error(), "missing port in address") {
return "", "", err
}
host = host + ":514"
}
return url.Scheme, host, nil
}
return "", "", nil
}
+6 -24
View File
@@ -15,39 +15,21 @@ func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) er
if err != nil {
return err
}
var preCpuStats types.CpuStats
getStat := func(v interface{}) *types.Stats {
enc := json.NewEncoder(out)
for v := range updates {
update := v.(*execdriver.ResourceStats)
ss := convertToAPITypes(update.Stats)
ss.PreCpuStats = preCpuStats
ss.MemoryStats.Limit = uint64(update.MemoryLimit)
ss.Read = update.Read
ss.CpuStats.SystemUsage = update.SystemUsage
preCpuStats = ss.CpuStats
return ss
}
enc := json.NewEncoder(out)
if !stream {
// prime the cpu stats so they aren't 0 in the final output
s := getStat(<-updates)
// now pull stats again with the cpu stats primed
s = getStat(<-updates)
err := enc.Encode(s)
daemon.UnsubscribeToContainerStats(name, updates)
return err
}
for v := range updates {
s := getStat(v)
if err := enc.Encode(s); err != nil {
if err := enc.Encode(ss); err != nil {
// TODO: handle the specific broken pipe
daemon.UnsubscribeToContainerStats(name, updates)
return err
}
if !stream {
break
}
}
return nil
}
+38 -92
View File
@@ -1,17 +1,16 @@
package daemon
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/local"
"github.com/docker/libcontainer/label"
)
@@ -53,13 +52,6 @@ func (m *mountPoint) Path() string {
return m.Source
}
// BackwardsCompatible decides whether this mount point can be
// used in old versions of Docker or not.
// Only bind mounts and local volumes can be used in old versions of Docker.
func (m *mountPoint) BackwardsCompatible() bool {
return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
}
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
bind := &mountPoint{
RW: true,
@@ -82,7 +74,7 @@ func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
}
name, source, err := parseVolumeSource(arr[0])
name, source, err := parseVolumeSource(arr[0], config)
if err != nil {
return nil, err
}
@@ -239,99 +231,53 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
mountPoints[bind.Destination] = bind
}
// Keep backwards compatible structures
bcVolumes := map[string]string{}
bcVolumesRW := map[string]bool{}
for _, m := range mountPoints {
if m.BackwardsCompatible() {
bcVolumes[m.Destination] = m.Path()
bcVolumesRW[m.Destination] = m.RW
}
}
container.Lock()
container.MountPoints = mountPoints
container.Volumes = bcVolumes
container.VolumesRW = bcVolumesRW
container.Unlock()
return nil
}
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
// verifyOldVolumesInfo ports volumes configured for the containers pre docker 1.7.
// It reads the container configuration and creates valid mount points for the old volumes.
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
// Inspect old structures only when we're upgrading from old versions
// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
for destination, hostPath := range container.Volumes {
vfsPath := filepath.Join(daemon.root, "vfs", "dir")
rw := container.VolumesRW != nil && container.VolumesRW[destination]
if strings.HasPrefix(hostPath, vfsPath) {
id := filepath.Base(hostPath)
if err := migrateVolume(id, hostPath); err != nil {
return err
}
container.addLocalMountPoint(id, destination, rw)
} else { // Bind mount
id, source, err := parseVolumeSource(hostPath)
// We should not find an error here coming
// from the old configuration, but who knows.
if err != nil {
return err
}
container.addBindMountPoint(id, source, destination, rw)
}
func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
jsonPath, err := container.jsonPath()
if err != nil {
return err
}
f, err := os.Open(jsonPath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
} else if len(container.MountPoints) > 0 {
// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
// with Docker 1.7 RC versions that put the information in
// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
l, err := getVolumeDriver(volume.DefaultDriverName)
if err != nil {
return err
}
for _, m := range container.MountPoints {
if m.Driver != volume.DefaultDriverName {
continue
}
dataPath := l.(*local.Root).DataPath(m.Name)
volumePath := filepath.Dir(dataPath)
d, err := ioutil.ReadDir(volumePath)
if err != nil {
// If the volume directory doesn't exist yet it will be recreated,
// so we only return the error when there is a different issue.
if !os.IsNotExist(err) {
return err
}
// Do not check when the volume directory does not exist.
continue
}
if validVolumeLayout(d) {
continue
}
if err := os.Mkdir(dataPath, 0755); err != nil {
return err
}
// Move data inside the data directory
for _, f := range d {
oldp := filepath.Join(volumePath, f.Name())
newp := filepath.Join(dataPath, f.Name())
if err := os.Rename(oldp, newp); err != nil {
logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
}
}
}
return container.ToDisk()
return err
}
return nil
type oldContVolCfg struct {
Volumes map[string]string
VolumesRW map[string]bool
}
vols := oldContVolCfg{
Volumes: make(map[string]string),
VolumesRW: make(map[string]bool),
}
if err := json.NewDecoder(f).Decode(&vols); err != nil {
return err
}
for destination, hostPath := range vols.Volumes {
vfsPath := filepath.Join(daemon.root, "vfs", "dir")
if strings.HasPrefix(hostPath, vfsPath) {
id := filepath.Base(hostPath)
rw := vols.VolumesRW != nil && vols.VolumesRW[destination]
container.addLocalMountPoint(id, destination, rw)
}
}
return container.ToDisk()
}
func createVolume(name, driverName string) (volume.Volume, error) {
+2 -1
View File
@@ -5,6 +5,7 @@ package daemon
import (
"path/filepath"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
)
@@ -16,7 +17,7 @@ func getVolumeDriver(name string) (volume.Driver, error) {
return volumedrivers.Lookup(name)
}
func parseVolumeSource(spec string) (string, string, error) {
func parseVolumeSource(spec string, config *runconfig.Config) (string, string, error) {
if !filepath.IsAbs(spec) {
return spec, "", nil
}
-49
View File
@@ -10,8 +10,6 @@ import (
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/local"
)
// copyOwnership copies the permissions and uid:gid of the source file
@@ -70,50 +68,3 @@ func (m mounts) Swap(i, j int) {
func (m mounts) parts(i int) int {
return len(strings.Split(filepath.Clean(m[i].Destination), string(os.PathSeparator)))
}
// migrateVolume links the contents of a volume created pre Docker 1.7
// into the location expected by the local driver.
// It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
// It preserves the volume json configuration generated pre Docker 1.7 to be able to
// downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
func migrateVolume(id, vfs string) error {
l, err := getVolumeDriver(volume.DefaultDriverName)
if err != nil {
return err
}
newDataPath := l.(*local.Root).DataPath(id)
fi, err := os.Stat(newDataPath)
if err != nil && !os.IsNotExist(err) {
return err
}
if fi != nil && fi.IsDir() {
return nil
}
return os.Symlink(vfs, newDataPath)
}
// validVolumeLayout checks whether the volume directory layout
// is valid to work with Docker post 1.7 or not.
func validVolumeLayout(files []os.FileInfo) bool {
if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
return true
}
if len(files) != 2 {
return false
}
for _, f := range files {
if f.Name() == "config.json" ||
(f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
// Old volume configuration, we ignore it
continue
}
return false
}
return true
}
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"path/filepath"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
)
@@ -14,7 +15,7 @@ func getVolumeDriver(_ string) (volume.Driver, error) {
return volumedrivers.Lookup(volume.DefaultDriverName)
}
func parseVolumeSource(spec string) (string, string, error) {
func parseVolumeSource(spec string, _ *runconfig.Config) (string, string, error) {
if !filepath.IsAbs(spec) {
return "", "", fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", spec)
}
+1 -13
View File
@@ -2,11 +2,7 @@
package daemon
import (
"os"
"github.com/docker/docker/daemon/execdriver"
)
import "github.com/docker/docker/daemon/execdriver"
// Not supported on Windows
func copyOwnership(source, destination string) error {
@@ -16,11 +12,3 @@ func copyOwnership(source, destination string) error {
func (container *Container) setupMounts() ([]execdriver.Mount, error) {
return nil, nil
}
func migrateVolume(id, vfs string) error {
return nil
}
func validVolumeLayout(files []os.FileInfo) bool {
return true
}
+1 -6
View File
@@ -16,7 +16,6 @@ import (
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/utils"
)
const (
@@ -162,9 +161,5 @@ func main() {
}
func showVersion() {
if utils.ExperimentalBuild() {
fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
} else {
fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
}
fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
}
+3
View File
@@ -1,2 +1,5 @@
# generated by man/man/md2man-all.sh
man1/
man5/
# avoid commiting the awsconfig file used for releases
awsconfig
+19 -6
View File
@@ -12,7 +12,7 @@ Docker has two primary branches for documentation:
| Branch | Description | URL (published via commit-hook) |
|----------|--------------------------------|------------------------------------------------------------------------------|
| `docs` | Official release documentation | [https://docs.docker.com](https://docs.docker.com) |
| `master` | Merged but unreleased development work | [http://docs.master.dockerproject.org](http://docs.master.dockerproject.org) |
| `master` | Merged but unreleased development work | [http://docs.master.dockerproject.com](http://docs.master.dockerproject.com) |
Additions and updates to upcoming releases are made in a feature branch off of
the `master` branch. The Docker maintainers also support a `docs` branch that
@@ -22,7 +22,7 @@ After a release, documentation updates are continually merged into `master` as
they occur. This work includes new documentation for forthcoming features, bug
fixes, and other updates. Docker's CI system automatically builds and updates
the `master` documentation after each merge and posts it to
[http://docs.master.dockerproject.org](http://docs.master.dockerproject.org).
[http://docs.master.dockerproject.com](http://docs.master.dockerproject.com).
Periodically, the Docker maintainers update `docs.docker.com` between official
releases of Docker. They do this by cherry-picking commits from `master`,
@@ -280,11 +280,24 @@ aws cloudfront create-invalidation --profile docs.docker.com --distribution-id
aws cloudfront create-invalidation --profile docs.docker.com --distribution-id $DISTRIBUTION_ID --invalidation-batch '{"Paths":{"Quantity":1, "Items":["/v1.1/reference/api/docker_io_oauth_api/"]},"CallerReference":"6Mar2015sventest1"}'
```
### Generate the man pages
### Generate the man pages for Mac OSX
For information on generating man pages (short for manual page), see [the man
page directory](https://github.com/docker/docker/tree/master/docker) in this
project.
When using Docker on Mac OSX the man pages will be missing by default. You can manually generate them by following these steps:
1. Checkout the docker source. You must clone into your `/Users` directory because Boot2Docker can only share this path
with the docker containers.
$ git clone https://github.com/docker/docker.git
2. Build the docker image.
$ cd docker/docs/man
$ docker build -t docker/md2man .
3. Build the man pages.
$ docker run -v /Users/<path-to-git-dir>/docker/docs/man:/docs:rw -w /docs -i docker/md2man /docs/md2man-all.sh
4. Copy the generated man pages to `/usr/share/man`
$ cp -R man* /usr/share/man/
+2 -2
View File
@@ -1,7 +1,7 @@
FROM golang:1.4
FROM golang:1.3
RUN mkdir -p /go/src/github.com/cpuguy83
RUN mkdir -p /go/src/github.com/cpuguy83 \
&& git clone -b v1.0.1 https://github.com/cpuguy83/go-md2man.git /go/src/github.com/cpuguy83/go-md2man \
&& git clone -b v1 https://github.com/cpuguy83/go-md2man.git /go/src/github.com/cpuguy83/go-md2man \
&& cd /go/src/github.com/cpuguy83/go-md2man \
&& go get -v ./...
CMD ["/go/bin/go-md2man", "--help"]
@@ -196,7 +196,7 @@ A Dockerfile is similar to a Makefile.
ADD <src> <dest>
# Required for paths with whitespace
ADD ["<src>",... "<dest>"]
ADD ["<src>", "<dest>"]
```
The **ADD** instruction copies new files, directories
@@ -215,7 +215,7 @@ A Dockerfile is similar to a Makefile.
COPY <src> <dest>
# Required for paths with whitespace
COPY ["<src>",... "<dest>"]
COPY ["<src>", "<dest>"]
```
The **COPY** instruction copies new files from `<src>` and
+33
View File
@@ -0,0 +1,33 @@
Docker Documentation
====================
This directory contains the Docker user manual in the Markdown format.
Do *not* edit the man pages in the man1 directory. Instead, amend the
Markdown (*.md) files.
# Generating man pages from the Markdown files
The recommended approach for generating the man pages is via a Docker
container using the supplied `Dockerfile` to create an image with the correct
environment. This uses `go-md2man`, a pure Go Markdown to man page generator.
## Building the md2man image
There is a `Dockerfile` provided in the `docker/docs/man` directory.
Using this `Dockerfile`, create a Docker image tagged `docker/md2man`:
docker build -t docker/md2man .
## Utilizing the image
Once the image is built, run a container using the image with *volumes*:
docker run -v /<path-to-git-dir>/docker/docs/man:/docs:rw \
-w /docs -i docker/md2man /docs/md2man-all.sh
The `md2man` Docker container will process the Markdown files and generate
the man pages inside the `docker/docs/man/man1` directory using
Docker volumes. For more information on Docker volumes see the man page for
`docker run` and also look at the article [Sharing Directories via Volumes]
(https://docs.docker.com/use/working_with_volumes/).
@@ -33,7 +33,6 @@ docker-create - Create a new container
[**--link**[=*[]*]]
[**--lxc-conf**[=*[]*]]
[**--log-driver**[=*[]*]]
[**--log-opt**[=*[]*]]
[**-m**|**--memory**[=*MEMORY*]]
[**--memory-swap**[=*MEMORY-SWAP*]]
[**--mac-address**[=*MAC-ADDRESS*]]
@@ -149,9 +148,6 @@ two memory nodes.
Logging driver for container. Default is defined by daemon `--log-driver` flag.
**Warning**: `docker logs` command works only for `json-file` logging driver.
**--log-opt**=[]
Logging driver specific options.
**-m**, **--memory**=""
Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
@@ -63,12 +63,7 @@ Again the output container IDs have been shortened for the purposes of this docu
2015-01-28T20:25:45.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) die
2015-01-28T20:25:46.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) stop
If you do not provide the --since option, the command returns only new and/or
live events.
# HISTORY
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work.
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
June 2015, updated by Brian Goff <cpuguy83@gmail.com>
@@ -34,7 +34,6 @@ docker-run - Run a command in a new container
[**--link**[=*[]*]]
[**--lxc-conf**[=*[]*]]
[**--log-driver**[=*[]*]]
[**--log-opt**[=*[]*]]
[**-m**|**--memory**[=*MEMORY*]]
[**--memory-swap**[=*MEMORY-SWAP*]]
[**--mac-address**[=*MAC-ADDRESS*]]
@@ -256,9 +255,6 @@ which interface and port to use.
Logging driver for container. Default is defined by daemon `--log-driver` flag.
**Warning**: `docker logs` command works only for `json-file` logging driver.
**--log-opt**=[]
Logging driver specific options.
**-m**, **--memory**=""
Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
-3
View File
@@ -105,9 +105,6 @@ unix://[/path/to/socket] to use.
Default driver for container logs. Default is `json-file`.
**Warning**: `docker logs` command works only for `json-file` logging driver.
**--log-opt**=[]
Logging driver specific options.
**--mtu**=VALUE
Set the containers network mtu. Default is `0`.
+6 -1
View File
@@ -1,5 +1,5 @@
site_name: Docker Documentation
#site_url: https://docs.docker.com/
#site_url: http://docs.docker.com/
site_url: /
site_description: Documentation for fast and lightweight Docker container based virtualization framework.
site_favicon: img/favicon.png
@@ -27,6 +27,11 @@ pages:
- ['index.md', 'About', 'Docker']
- ['introduction/understanding-docker.md', 'About', 'Understanding Docker']
- ['release-notes.md', 'About', 'Release notes']
# Experimental
- ['experimental/experimental.md', 'About', 'Experimental Features']
- ['experimental/plugin_api.md', '**HIDDEN**']
- ['experimental/plugins_volume.md', '**HIDDEN**']
- ['experimental/plugins.md', '**HIDDEN**']
- ['reference/glossary.md', 'About', 'Glossary']
- ['introduction/index.md', '**HIDDEN**']
+4 -23
View File
@@ -24,28 +24,14 @@ If you want Docker to start at boot, you should also:
## Custom Docker daemon options
There are a number of ways to configure the daemon flags and environment variables
for your Docker daemon.
for your Docker daemon.
If the `docker.service` file is set to use an `EnvironmentFile`
(often pointing to `/etc/sysconfig/docker`) then you can modify the
referenced file.
Check if the `docker.service` uses an `EnvironmentFile`:
$ sudo systemctl show docker | grep EnvironmentFile
EnvironmentFile=-/etc/sysconfig/docker (ignore_errors=yes)
Alternatively, find out where the service file is located, and look for the
property:
$ sudo systemctl status docker | grep Loaded
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled)
$ sudo grep EnvironmentFile /usr/lib/systemd/system/docker.service
EnvironmentFile=-/etc/sysconfig/docker
You can customize the Docker daemon options using override files as explained in the
[HTTP Proxy example](#http-proxy) below. The files located in `/usr/lib/systemd/system`
or `/lib/systemd/system` contain the default options and should not be edited.
Or, you may need to edit the `docker.service` file, which can be in
`/usr/lib/systemd/system`, `/etc/systemd/service`, or `/lib/systemd/system`.
### Runtime directory and storage driver
@@ -56,7 +42,7 @@ In this example, we'll assume that your `docker.service` file looks something li
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
Documentation=http://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
@@ -104,11 +90,6 @@ Flush changes:
$ sudo systemctl daemon-reload
Verify that the configuration has been loaded:
$ sudo systemctl show docker --property Environment
Environment=HTTP_PROXY=http://proxy.example.com:80/
Restart Docker:
$ sudo systemctl restart docker
@@ -1,4 +1,3 @@
no_version_dropdown: true
page_title: Docker Hub Enterprise: Admin guide
page_description: Documentation describing administration of Docker Hub Enterprise
page_keywords: docker, documentation, about, technology, hub, enterprise
@@ -1,4 +1,3 @@
no_version_dropdown: true
page_title: Docker Hub Enterprise: Configuration options
page_description: Configuration instructions for Docker Hub Enterprise
page_keywords: docker, documentation, about, technology, understanding, enterprise, hub, registry
@@ -137,11 +136,11 @@ Continue by following the steps corresponding to your chosen OS.
```
$ export DOMAIN_NAME=dhe.yourdomain.com
$ openssl s_client -connect $DOMAIN_NAME:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | sudo tee /usr/local/share/ca-certificates/$DOMAIN_NAME.crt
$ sudo update-ca-certificates
$ openssl s_client -connect $DOMAIN_NAME:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | tee /usr/local/share/ca-certificates/$DOMAIN_NAME.crt
$ update-ca-certificates
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
$ sudo service docker restart
$ service docker restart
docker stop/waiting
docker start/running, process 29291
```
@@ -150,9 +149,9 @@ Continue by following the steps corresponding to your chosen OS.
```
$ export DOMAIN_NAME=dhe.yourdomain.com
$ openssl s_client -connect $DOMAIN_NAME:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | sudo tee /etc/pki/ca-trust/source/anchors/$DOMAIN_NAME.crt
$ sudo update-ca-trust
$ sudo /bin/systemctl restart docker.service
$ openssl s_client -connect $DOMAIN_NAME:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | tee /etc/pki/ca-trust/source/anchors/$DOMAIN_NAME.crt
$ update-ca-trust
$ /bin/systemctl restart docker.service
```
#### Boot2Docker 1.6.0
@@ -258,7 +257,7 @@ API.
* *Yaml configuration file*: This file (`/usr/local/etc/dhe/storage.yml`) is
used to configure the image storage services. The editable text of the file is
displayed in the dialog box. The schema of this file is identical to that used
by the [Registry 2.0](https://docs.docker.com/registry/configuration/).
by the [Registry 2.0](http://docs.docker.com/registry/configuration/).
* If you are using the file system driver to provide local image storage, you will need to specify a root directory which will get mounted as a sub-path of
`/var/local/dhe/image-storage`. The default value of this root directory is
`/local`, so the full path to it is `/var/local/dhe/image-storage/local`.
@@ -1,4 +1,3 @@
no_version_dropdown: true
page_title: Docker Hub Enterprise: Overview
page_description: Docker Hub Enterprise
page_keywords: docker, documentation, about, technology, understanding, enterprise, hub, registry
@@ -32,12 +31,6 @@ DHE is perfect for:
DHE is built on [version 2 of the Docker registry](https://github.com/docker/distribution).
> **Note:** This initial release of DHE has limited access. To get access,
> you will need an account on [Docker Hub](https://hub.docker.com/). Once you're
> logged in to the Hub with your account, visit the
> [early access registration page](https://registry.hub.docker.com/earlyaccess/)
> and follow the steps there to get signed up.
## Available Documentation
The following documentation for DHE is available:
+3 -18
View File
@@ -1,4 +1,3 @@
no_version_dropdown: true
page_title: Docker Hub Enterprise: Install
page_description: Installation instructions for Docker Hub Enterprise
page_keywords: docker, documentation, about, technology, understanding, enterprise, hub, registry
@@ -21,12 +20,6 @@ Specifically, installation requires completion of these steps, in order:
3. Install DHE
4. Add your license to your DHE instance
> **Note:** This initial release of DHE has limited access. To get access,
> you will need an account on [Docker Hub](https://hub.docker.com/). Once you're
> logged in to the Hub with your account, visit the
> [early access registration page](https://registry.hub.docker.com/earlyaccess/)
> and follow the steps there to get signed up.
## Licensing
In order to run DHE, you will need to acquire a license, either by purchasing
@@ -115,8 +108,6 @@ following to install commercially supported Docker Engine and its dependencies:
```
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt-get install -y linux-image-extra-virtual
$ sudo reboot
$ chmod 755 docker-cs-engine-deb.sh
$ sudo ./docker-cs-engine-deb.sh
$ sudo apt-get install docker-engine-cs
@@ -148,25 +139,19 @@ so upgrading the Engine only requires you to run the update commands on your ser
### RHEL 7.0/7.1 upgrade
The following commands will stop the running DHE, upgrade CS Docker Engine,
and then start DHE again:
To upgrade CS Docker Engine, run the following command:
```
$ sudo bash -c "$(sudo docker run dockerhubenterprise/manager stop)"
$ sudo yum update
$ sudo systemctl daemon-reload && sudo systemctl restart docker
$ sudo bash -c "$(sudo docker run dockerhubenterprise/manager start)"
```
### Ubuntu 14.04 LTS upgrade
The following commands will stop the running DHE, upgrade CS Docker Engine,
and then start DHE again:
To upgrade CS Docker Engine, run the following command:
```
$ sudo bash -c "$(sudo docker run dockerhubenterprise/manager stop)"
$ sudo apt-get update && sudo apt-get dist-upgrade docker-engine-cs
$ sudo bash -c "$(sudo docker run dockerhubenterprise/manager start)"
$ sudo apt-get update && sudo apt-get dist-upgrade docker-engine-cs
```
## Installing Docker Hub Enterprise
@@ -1,4 +1,3 @@
no_version_dropdown: true
page_title: Docker Hub Enterprise: Quick-start: Basic Workflow
page_description: Brief tutorial on the basics of Docker Hub Enterprise user workflow
page_keywords: docker, documentation, about, technology, understanding, enterprise, hub, registry, image, repository
@@ -9,7 +8,7 @@ page_keywords: docker, documentation, about, technology, understanding, enterpri
## Overview
This Quick Start Guide will give you a hands-on look at the basics of using
Docker Hub Enterprise (DHE), Docker's on-premise image storage application.
Docker Hub Enterprise (DHE), Dockers on-premise image storage application.
This guide will walk you through using DHE to complete a typical, and critical,
part of building a development pipeline: setting up a Jenkins instance. Once you
complete the task, you should have a good idea of how DHE works and how it might
@@ -18,9 +17,9 @@ be useful to you.
Specifically, this guide demonstrates the process of retrieving the
[official Docker image for Jenkins](https://registry.hub.docker.com/_/jenkins/),
customizing it to suit your needs, and then hosting it on your private instance
of DHE located inside your enterprise's firewalled environment. Your developers
of DHE located inside your enterprises firewalled environment. Your developers
will then be able to retrieve the custom Jenkins image in order to use it to
build CI/CD infrastructure for their projects, no matter the platform they're
build CI/CD infrastructure for their projects, no matter the platform theyre
working from, be it a laptop, a VM, or a cloud provider.
The guide will walk you through the following steps:
@@ -45,7 +44,7 @@ You should be able to complete this guide in about thirty minutes.
> **Note:** This guide assumes you are familiar with basic Docker concepts such
> as images, containers, and registries. If you need to learn more about Docker
> fundamentals, please consult the
> [Docker user guide](https://docs.docker.com/userguide/).
> [Docker user guide](http://docs.docker.com/userguide/).
First, you will retrieve a copy of the official Jenkins image from the Docker Hub. By default, if
Docker can't find an image locally, it will attempt to pull the image from the
@@ -73,12 +72,12 @@ Docker will start the process of pulling the image from the Hub. Once it has com
## Customizing the Jenkins image
Now that you have a local copy of the Jenkins image, you'll customize it so that
Now that you have a local copy of the Jenkins image, youll customize it so that
the containers it builds will integrate with your infrastructure. To do this,
you'll create a custom Docker image that adds a Jenkins plugin that provides
fine grained user management. You'll also configure Jenkins to be more secure by
youll create a custom Docker image that adds a Jenkins plugin that provides
fine grained user management. Youll also configure Jenkins to be more secure by
disabling HTTP access and forcing it to use HTTPS.
You'll do this by using a `Dockerfile` and the `docker build` command.
Youll do this by using a `Dockerfile` and the `docker build` command.
> **Note:** These are obviously just a couple of examples of the many ways you
> can modify and configure Jenkins. Feel free to add or substitute whatever
@@ -106,11 +105,11 @@ line:
(The plugin version used above was the latest version at the time of writing.)
2. You will also need to make copies of the server's private key and certificate. Give the copies the following names - `https.key` and `https.pem`.
2. You will also need to make copies of the servers private key and certificate. Give the copies the following names `https.key` and `https.pem`.
> **Note:** Because creating new keys varies widely by platform and
> implementation, this guide won't cover key generation. We assume you have
> access to existing keys. If you don't have access, or can't generate keys
> implementation, this guide wont cover key generation. We assume you have
> access to existing keys. If you dont have access, or cant generate keys
> yourself, feel free to skip the steps involving them and HTTPS config. The
> guide will still walk you through building a custom Jenkins image and pushing
> and pulling that image using DHE.
@@ -143,7 +142,7 @@ defining with the `Dockerfile`.
The `RUN` instruction will execute the `/usr/local/bin/plugins.sh` script with
the newly copied `plugins` file, which will install the listed plugin.
The next two `COPY` instructions copy the server's private key and certificate
The next two `COPY` instructions copy the servers private key and certificate
into the required directories within the new image.
The `ENV` instruction creates an environment variable called `JENKINS_OPT` in
@@ -157,8 +156,8 @@ tell Jenkins to disable HTTP and operate over HTTPS.
The `Dockerfile`, the `plugins` file, as well as the private key and
certificate, must all be in the same directory because the `docker build`
command uses the directory that contains the `Dockerfile` as its "build
context". Only files contained within that "build context" will be included in
command uses the directory that contains the `Dockerfile` as its build
context. Only files contained within that build context will be included in
the image being built.
### Building your custom image
@@ -170,7 +169,7 @@ custom image using the
docker build -t dhe.yourdomain.com/ci-infrastructure/jnkns-img .
> **Note:** Don't miss the period (`.`) at the end of the command above. This
> **Note:** Dont miss the period (`.`) at the end of the command above. This
> tells the `docker build` command to use the current working directory as the
> "build context".
@@ -215,7 +214,7 @@ image pulled earlier:
> ?scope=repository%3Ahello-world%3Apull%2Cpush&service=dhe.yourdomain.com
> request failed with status: 401 Unauthorized
Now that you've created the custom image, it can be pushed to DHE using the
Now that youve created the custom image, it can be pushed to DHE using the
[`docker push`command](https://docs.docker.com/reference/commandline/cli/#push):
$ docker push dhe.yourdomain.com/ci-infrastructure/jnkns-img
@@ -264,7 +263,7 @@ in the output of the `docker images` command:
## Launching a custom Jenkins container
Now that you've successfully pulled the customized Jenkins image from DHE, you
Now that youve successfully pulled the customized Jenkins image from DHE, you
can create a container from it with the
[`docker run` command](https://docs.docker.com/reference/commandline/cli/#run):
@@ -300,7 +299,7 @@ You can view the newly launched a container, called `jenkins01`, using the
The previous `docker run` command mapped port `1973` on the container to port
`1973` on the Docker host, so the Jenkins Web UI can be accessed at
`https://<docker-host>:1973` (Don't forget the `s` at the end of `https`.)
`https://<docker-host>:1973` (Dont forget the `s` at the end of `https`.)
> **Note:** If you are using a self-signed certificate, you may get a security
> warning from your browser telling you that the certificate is self-signed and
@@ -316,7 +315,7 @@ plugin should be present with the `Uninstall` button available to the right.
![Jenkins plugin manager](../assets/jenkins-plugins.png)
In another browser session, try to access Jenkins via the default HTTP port 8080
`http://<docker-host>:8080`. This should result in a "connection timeout",
`http://<docker-host>:8080`. This should result in a connection timeout,
showing that Jenkins is not available on its default port 8080 over HTTP.
This demonstration shows your Jenkins image has been configured correctly for

Some files were not shown because too many files have changed in this diff Show More