Docker installation from tar.gz

Ubuntu 18.04 doesn't have a package for docker 17.03, but we can still
support it by using the tar.gz package.

This could be a nice fallback for other operating systems in future,
and it might prove to be more reliable than the OS packages.

But start with supporting ubuntu 18.04 with older docker versions!
This commit is contained in:
Justin Santa Barbara 2018-07-24 21:56:46 -04:00
parent 86e8820a7e
commit 2faa68426f
5 changed files with 214 additions and 9 deletions

View File

@ -52,6 +52,9 @@ type dockerVersion struct {
Distros []distros.Distribution
Dependencies []string
Architectures []Architecture
// PlainBinary indicates that the Source is not an OS, but a "bare" tar.gz
PlainBinary bool
}
// DefaultDockerVersion is the (legacy) docker version we use if one is not specified in the manifest.
@ -414,6 +417,17 @@ var dockerVersions = []dockerVersion{
Dependencies: []string{"bridge-utils", "iptables", "libapparmor1", "libltdl7", "perl"},
},
// 17.03.2 - Ubuntu Bionic via binary download (no packages available)
{
DockerVersion: "17.03.2",
PlainBinary: true,
Distros: []distros.Distribution{distros.DistributionBionic},
Architectures: []Architecture{ArchitectureAmd64},
Source: "http://download.docker.com/linux/static/stable/x86_64/docker-17.03.2-ce.tgz",
Hash: "141716ae046016a1792ce232a0f4c8eed7fe37d1",
Dependencies: []string{"bridge-utils", "iptables", "libapparmor1", "libltdl7", "perl"},
},
// 17.03.2 - Centos / Rhel7 (two packages)
{
DockerVersion: "17.03.2",
@ -591,15 +605,28 @@ func (b *DockerBuilder) Build(c *fi.ModelBuilderContext) error {
count++
c.AddTask(&nodetasks.Package{
Name: dv.Name,
Version: s(dv.Version),
Source: s(dv.Source),
Hash: s(dv.Hash),
if dv.PlainBinary {
c.AddTask(&nodetasks.Archive{
Name: "docker",
Source: dv.Source,
Hash: dv.Hash,
TargetDir: "/usr/bin/",
StripComponents: 1,
})
// TODO: PreventStart is now unused?
PreventStart: fi.Bool(true),
})
c.AddTask(b.buildDockerGroup())
c.AddTask(b.buildSystemdSocket())
} else {
c.AddTask(&nodetasks.Package{
Name: dv.Name,
Version: s(dv.Version),
Source: s(dv.Source),
Hash: s(dv.Hash),
// TODO: PreventStart is now unused?
PreventStart: fi.Bool(true),
})
}
for _, dep := range dv.Dependencies {
c.AddTask(&nodetasks.Package{Name: dep})
@ -640,6 +667,40 @@ func (b *DockerBuilder) Build(c *fi.ModelBuilderContext) error {
return nil
}
// buildDockerGroup creates the docker group, which owns the docker.socket
func (b *DockerBuilder) buildDockerGroup() *nodetasks.GroupTask {
return &nodetasks.GroupTask{
Name: "docker",
System: true,
}
}
// buildSystemdSocket creates docker.socket, for when we're not installing from a package
func (b *DockerBuilder) buildSystemdSocket() *nodetasks.Service {
manifest := &systemd.Manifest{}
manifest.Set("Unit", "Description", "Docker Socket for the API")
manifest.Set("Unit", "PartOf", "docker.service")
manifest.Set("Socket", "ListenStream", "/var/run/docker.sock")
manifest.Set("Socket", "SocketMode", "0660")
manifest.Set("Socket", "SocketUser", "root")
manifest.Set("Socket", "SocketGroup", "docker")
manifest.Set("Install", "WantedBy", "sockets.target")
manifestString := manifest.Render()
glog.V(8).Infof("Built docker.socket manifest\n%s", manifestString)
service := &nodetasks.Service{
Name: "docker.socket",
Definition: s(manifestString),
}
service.InitDefaults()
return service
}
func (b *DockerBuilder) buildSystemdService(dockerVersionMajor int64, dockerVersionMinor int64) *nodetasks.Service {
oldDocker := dockerVersionMajor <= 1 && dockerVersionMinor <= 11
usesDockerSocket := true

View File

@ -8,6 +8,7 @@ go_library(
"bindmount.go",
"createsdir.go",
"file.go",
"group.go",
"load_image.go",
"mount_disk.go",
"package.go",

View File

@ -24,6 +24,7 @@ import (
"os/exec"
"path"
"reflect"
"strconv"
"github.com/golang/glog"
"k8s.io/kops/upup/pkg/fi"
@ -43,6 +44,9 @@ type Archive struct {
// TargetDir is the directory for extraction
TargetDir string `json:"target,omitempty"`
// StripComponents is the number of components to remove when expanding the archive
StripComponents int `json:"stripComponents,omitempty"`
}
const (
@ -159,6 +163,10 @@ func (_ *Archive) RenderLocal(t *local.LocalTarget, a, e, changes *Archive) erro
}
args := []string{"tar", "xf", localFile, "-C", targetDir}
if e.StripComponents != 0 {
args = append(args, "--strip-components="+strconv.Itoa(e.StripComponents))
}
glog.Infof("running command %s", args)
cmd := exec.Command(args[0], args[1:]...)
if output, err := cmd.CombinedOutput(); err != nil {

View File

@ -0,0 +1,135 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nodetasks
import (
"fmt"
"os/exec"
"strconv"
"strings"
"github.com/golang/glog"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/nodeup/cloudinit"
"k8s.io/kops/upup/pkg/fi/nodeup/local"
)
// GroupTask is responsible for creating a group, by calling groupadd
type GroupTask struct {
Name string
GID *int
System bool
}
var _ fi.Task = &GroupTask{}
func (e *GroupTask) String() string {
return fmt.Sprintf("Group: %s", e.Name)
}
var _ fi.HasName = &File{}
func (f *GroupTask) GetName() *string {
return &f.Name
}
func (f *GroupTask) SetName(name string) {
glog.Fatalf("SetName not supported for Group task")
}
func (e *GroupTask) Find(c *fi.Context) (*GroupTask, error) {
info, err := fi.LookupGroup(e.Name)
if err != nil {
return nil, err
}
if info == nil {
return nil, nil
}
gid := info.Gid
actual := &GroupTask{
Name: e.Name,
GID: &gid,
}
// Avoid spurious changes
actual.System = e.System
return actual, nil
}
func (e *GroupTask) Run(c *fi.Context) error {
return fi.DefaultDeltaRunMethod(e, c)
}
func (_ *GroupTask) CheckChanges(a, e, changes *GroupTask) error {
return nil
}
func buildGroupaddArgs(e *GroupTask) []string {
var args []string
if e.GID != nil {
args = append(args, "-g", strconv.Itoa(*e.GID))
}
if e.System {
args = append(args, "--system")
}
args = append(args, e.Name)
return args
}
func (_ *GroupTask) RenderLocal(t *local.LocalTarget, a, e, changes *GroupTask) error {
if a == nil {
args := buildGroupaddArgs(e)
glog.Infof("Creating group %q", e.Name)
cmd := exec.Command("groupadd", args...)
glog.V(2).Infof("running command: groupadd %s", strings.Join(args, " "))
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error creating group: %v\nOutput: %s", err, output)
}
} else {
var args []string
if changes.GID != nil {
args = append(args, "-g", strconv.Itoa(*e.GID))
}
if len(args) != 0 {
args = append(args, e.Name)
glog.Infof("Reconfiguring group %q", e.Name)
cmd := exec.Command("groupmod", args...)
glog.V(2).Infof("running command: groupmod %s", strings.Join(args, " "))
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error reconfiguring group: %v\nOutput: %s", err, output)
}
}
}
return nil
}
func (_ *GroupTask) RenderCloudInit(t *cloudinit.CloudInitTarget, a, e, changes *GroupTask) error {
args := buildGroupaddArgs(e)
cmd := []string{"groupadd"}
cmd = append(cmd, args...)
glog.Infof("Creating group %q", e.Name)
t.AddCommand(cloudinit.Once, cmd...)
return nil
}

View File

@ -70,7 +70,7 @@ func (p *Service) GetDependencies(tasks map[string]fi.Task) []fi.Task {
// launching a custom Kubernetes build), they all depend on
// the "docker.service" Service task.
switch v.(type) {
case *File, *Package, *UpdatePackages, *UserTask, *MountDiskTask:
case *File, *Package, *UpdatePackages, *UserTask, *GroupTask, *MountDiskTask:
deps = append(deps, v)
case *Service, *LoadImageTask:
// ignore