mirror of https://github.com/docker/docs.git
Merge pull request #1090 from ehazlett/redhat-provisioning
RedHat provisioning
This commit is contained in:
commit
9bf7812473
|
@ -1110,6 +1110,8 @@ Options:
|
|||
|
||||
The DigitalOcean driver will use `ubuntu-14-04-x64` as the default image.
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
Environment variables and default values:
|
||||
|
||||
| CLI option | Environment variable | Default |
|
||||
|
@ -1121,6 +1123,21 @@ Environment variables and default values:
|
|||
| `--digitalocean-ipv6` | `DIGITALOCEAN_IPV6` | `false` |
|
||||
| `--digitalocean-private-networking` | `DIGITALOCEAN_PRIVATE_NETWORKING` | `false` |
|
||||
| `--digitalocean-backups` | `DIGITALOCEAN_BACKUPS` | `false` |
|
||||
=======
|
||||
#### exoscale
|
||||
Create machines on [exoscale](https://www.exoscale.ch/).
|
||||
|
||||
Get your API key and API secret key from [API details](https://portal.exoscale.ch/account/api) and pass them to `machine create` with the `--exoscale-api-key` and `--exoscale-api-secret-key` options.
|
||||
|
||||
Options:
|
||||
|
||||
- `--exoscale-api-key`: Your API key.
|
||||
- `--exoscale-api-secret-key`: Your API secret key.
|
||||
- `--exoscale-instance-profile`: Instance profile. Default: `small`.
|
||||
- `--exoscale-disk-size`: Disk size for the host in GB. Default: `50`.
|
||||
- `--exoscale-security-group`: Security group. It will be created if it doesn't exist. Default: `docker-machine`.
|
||||
|
||||
If a custom security group is provided, you need to ensure that you allow TCP port 2376 in an ingress rule.
|
||||
|
||||
#### Generic
|
||||
Create machines using an existing VM/Host with SSH.
|
||||
|
@ -1513,6 +1530,8 @@ Options:
|
|||
|
||||
The VMware vSphere driver uses the latest boot2docker image.
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
Environment variables and default values:
|
||||
|
||||
| CLI option | Environment variable | Default |
|
||||
|
@ -1563,6 +1582,16 @@ Environment variables and default values:
|
|||
| `--exoscale-availability-zone` | `EXOSCALE_AVAILABILITY_ZONE` | `ch-gva-2` |
|
||||
| `--exoscale-keypair` | `EXOSCALE_KEYPAIR` | - |
|
||||
|
||||
=======
|
||||
|
||||
## Base Operating Systems
|
||||
The default base operating system for Machine is Boot2Docker on local providers
|
||||
(VirtualBox, Fusion, Hyper-V, etc) and the latest Ubuntu LTS supported
|
||||
by the cloud provider. RedHat Enterprise Linux is also supported. To use
|
||||
RHEL, you will need to select the image accordingly with the provider. For
|
||||
example, in Amazon EC2, you could use a RedHat 7.1 AMI ("ami-12663b7a") as the
|
||||
`--amazonec2-ami` option which create an instance using RHEL 7.1 64-bit.
|
||||
|
||||
## Release Notes
|
||||
|
||||
### Version 0.2.0 (April 16, 2015)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package provision
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: eventually the RPM install process will be integrated
|
||||
// into the get.docker.com install script; for now
|
||||
// we install via vendored RPMs
|
||||
dockerCentosRPMPath = "https://docker-mcn.s3.amazonaws.com/public/redhat/rpms/docker-engine-1.6.1-0.0.20150511.171646.git1b47f9f.el7.centos.x86_64.rpm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("Centos", &RegisteredProvisioner{
|
||||
New: NewCentosProvisioner,
|
||||
})
|
||||
}
|
||||
|
||||
func NewCentosProvisioner(d drivers.Driver) Provisioner {
|
||||
g := GenericProvisioner{
|
||||
DockerOptionsDir: "/etc/docker",
|
||||
DaemonOptionsFile: "/etc/systemd/system/docker.service",
|
||||
OsReleaseId: "centos",
|
||||
Packages: []string{},
|
||||
Driver: d,
|
||||
}
|
||||
p := &CentosProvisioner{
|
||||
RedHatProvisioner{
|
||||
GenericProvisioner: g,
|
||||
DockerRPMPath: dockerCentosRPMPath,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type CentosProvisioner struct {
|
||||
RedHatProvisioner
|
||||
}
|
|
@ -6,7 +6,8 @@ import (
|
|||
)
|
||||
|
||||
type EngineConfigContext struct {
|
||||
DockerPort int
|
||||
AuthOptions auth.AuthOptions
|
||||
EngineOptions engine.EngineOptions
|
||||
DockerPort int
|
||||
AuthOptions auth.AuthOptions
|
||||
EngineOptions engine.EngineOptions
|
||||
DockerOptionsDir string
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package provision
|
||||
|
||||
import (
|
||||
"github.com/docker/machine/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: eventually the RPM install process will be integrated
|
||||
// into the get.docker.com install script; for now
|
||||
// we install via vendored RPMs
|
||||
dockerFedoraRPMPath = "https://docker-mcn.s3.amazonaws.com/public/fedora/rpms/docker-engine-1.6.1-0.0.20150511.171646.git1b47f9f.fc21.x86_64.rpm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("Fedora", &RegisteredProvisioner{
|
||||
New: NewFedoraProvisioner,
|
||||
})
|
||||
}
|
||||
|
||||
func NewFedoraProvisioner(d drivers.Driver) Provisioner {
|
||||
g := GenericProvisioner{
|
||||
DockerOptionsDir: "/etc/docker",
|
||||
DaemonOptionsFile: "/etc/systemd/system/docker.service",
|
||||
OsReleaseId: "fedora",
|
||||
Packages: []string{},
|
||||
Driver: d,
|
||||
}
|
||||
p := &FedoraProvisioner{
|
||||
RedHatProvisioner{
|
||||
GenericProvisioner: g,
|
||||
DockerRPMPath: dockerFedoraRPMPath,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type FedoraProvisioner struct {
|
||||
RedHatProvisioner
|
||||
}
|
|
@ -6,12 +6,18 @@ const (
|
|||
Restart ServiceAction = iota
|
||||
Start
|
||||
Stop
|
||||
Enable
|
||||
Disable
|
||||
DaemonReload
|
||||
)
|
||||
|
||||
var serviceActions = []string{
|
||||
"restart",
|
||||
"start",
|
||||
"stop",
|
||||
"enable",
|
||||
"disable",
|
||||
"daemon-reload",
|
||||
}
|
||||
|
||||
func (s ServiceAction) String() string {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/docker/machine/libmachine/engine"
|
||||
"github.com/docker/machine/libmachine/provision/pkgaction"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/docker/machine/log"
|
||||
)
|
||||
|
||||
var provisioners = make(map[string]*RegisteredProvisioner)
|
||||
|
@ -82,6 +83,7 @@ func DetectProvisioner(d drivers.Driver) (Provisioner, error) {
|
|||
provisioner.SetOsReleaseInfo(osReleaseInfo)
|
||||
|
||||
if provisioner.CompatibleWithHost() {
|
||||
log.Debugf("Compatible OS: %s", osReleaseInfo.Id)
|
||||
return provisioner, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package provision
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/engine"
|
||||
"github.com/docker/machine/libmachine/provision/pkgaction"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/docker/machine/log"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO: eventually the RPM install process will be integrated
|
||||
// into the get.docker.com install script; for now
|
||||
// we install via vendored RPMs
|
||||
dockerRHELRPMPath = "https://docker-mcn.s3.amazonaws.com/public/redhat/rpms/docker-engine-1.6.1-0.0.20150511.171646.git1b47f9f.el7.centos.x86_64.rpm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("RedHat", &RegisteredProvisioner{
|
||||
New: NewRedHatProvisioner,
|
||||
})
|
||||
}
|
||||
|
||||
func NewRedHatProvisioner(d drivers.Driver) Provisioner {
|
||||
return &RedHatProvisioner{
|
||||
GenericProvisioner: GenericProvisioner{
|
||||
DockerOptionsDir: "/etc/docker",
|
||||
DaemonOptionsFile: "/etc/systemd/system/docker.service",
|
||||
OsReleaseId: "rhel",
|
||||
Packages: []string{
|
||||
"curl",
|
||||
},
|
||||
Driver: d,
|
||||
},
|
||||
DockerRPMPath: dockerRHELRPMPath,
|
||||
}
|
||||
}
|
||||
|
||||
type RedHatProvisioner struct {
|
||||
GenericProvisioner
|
||||
DockerRPMPath string
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) Service(name string, action pkgaction.ServiceAction) error {
|
||||
reloadDaemon := false
|
||||
switch action {
|
||||
case pkgaction.Start, pkgaction.Restart:
|
||||
reloadDaemon = true
|
||||
}
|
||||
|
||||
// systemd needs reloaded when config changes on disk; we cannot
|
||||
// be sure exactly when it changes from the provisioner so
|
||||
// we call a reload on every restart to be safe
|
||||
if reloadDaemon {
|
||||
if _, err := provisioner.SSHCommand("sudo systemctl daemon-reload"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
command := fmt.Sprintf("sudo systemctl %s %s", action.String(), name)
|
||||
|
||||
if _, err := provisioner.SSHCommand(command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) Package(name string, action pkgaction.PackageAction) error {
|
||||
var packageAction string
|
||||
|
||||
switch action {
|
||||
case pkgaction.Install:
|
||||
packageAction = "install"
|
||||
case pkgaction.Remove:
|
||||
packageAction = "remove"
|
||||
case pkgaction.Upgrade:
|
||||
packageAction = "upgrade"
|
||||
}
|
||||
|
||||
command := fmt.Sprintf("sudo -E yum %s -y %s", packageAction, name)
|
||||
|
||||
if _, err := provisioner.SSHCommand(command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installDocker(provisioner *RedHatProvisioner) error {
|
||||
if err := provisioner.installOfficialDocker(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provisioner.Service("docker", pkgaction.Restart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := provisioner.Service("docker", pkgaction.Enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) installOfficialDocker() error {
|
||||
log.Debug("installing docker")
|
||||
|
||||
if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo yum install -y --nogpgcheck %s", provisioner.DockerRPMPath)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) dockerDaemonResponding() bool {
|
||||
if _, err := provisioner.SSHCommand("sudo docker version"); err != nil {
|
||||
log.Warn("Error getting SSH command to check if the daemon is up: %s", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// The daemon is up if the command worked. Carry on.
|
||||
return true
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
|
||||
provisioner.SwarmOptions = swarmOptions
|
||||
provisioner.AuthOptions = authOptions
|
||||
provisioner.EngineOptions = engineOptions
|
||||
|
||||
// set default storage driver for redhat
|
||||
if provisioner.EngineOptions.StorageDriver == "" {
|
||||
provisioner.EngineOptions.StorageDriver = "devicemapper"
|
||||
}
|
||||
|
||||
if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range provisioner.Packages {
|
||||
log.Debugf("installing base package: name=%s", pkg)
|
||||
if err := provisioner.Package(pkg, pkgaction.Install); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// update OS -- this is needed for libdevicemapper and the docker install
|
||||
if _, err := provisioner.SSHCommand("sudo yum -y update"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// install docker
|
||||
if err := installDocker(provisioner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.WaitFor(provisioner.dockerDaemonResponding); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := makeDockerOptionsDir(provisioner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provisioner.AuthOptions = setRemoteAuthOptions(provisioner)
|
||||
|
||||
if err := ConfigureAuth(provisioner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := configureSwarm(provisioner, swarmOptions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provisioner *RedHatProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
|
||||
var (
|
||||
engineCfg bytes.Buffer
|
||||
configPath = provisioner.DaemonOptionsFile
|
||||
)
|
||||
|
||||
// remove existing
|
||||
//if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo rm %s", configPath)); err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
|
||||
driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
|
||||
provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)
|
||||
|
||||
// systemd / redhat will not load options if they are on newlines
|
||||
// instead, it just continues with a different set of options; yeah...
|
||||
engineConfigTmpl := `[Service]
|
||||
ExecStart=/usr/bin/docker -d -H tcp://0.0.0.0:{{.DockerPort}} -H unix:///var/run/docker.sock --storage-driver {{.EngineOptions.StorageDriver}} --tlsverify --tlscacert {{.AuthOptions.CaCertRemotePath}} --tlscert {{.AuthOptions.ServerCertRemotePath}} --tlskey {{.AuthOptions.ServerKeyRemotePath}} {{ range .EngineOptions.Labels }}--label {{.}} {{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}} {{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}} {{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}} {{ end }}
|
||||
MountFlags=slave
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
`
|
||||
t, err := template.New("engineConfig").Parse(engineConfigTmpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
engineConfigContext := EngineConfigContext{
|
||||
DockerPort: dockerPort,
|
||||
AuthOptions: provisioner.AuthOptions,
|
||||
EngineOptions: provisioner.EngineOptions,
|
||||
DockerOptionsDir: provisioner.DockerOptionsDir,
|
||||
}
|
||||
|
||||
t.Execute(&engineCfg, engineConfigContext)
|
||||
|
||||
daemonOptsDir := configPath
|
||||
return &DockerOptions{
|
||||
EngineOptions: engineCfg.String(),
|
||||
EngineOptionsPath: daemonOptsDir,
|
||||
}, nil
|
||||
}
|
|
@ -101,6 +101,7 @@ func ConfigureAuth(p Provisioner) error {
|
|||
org,
|
||||
bits,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating server cert: %s", err)
|
||||
}
|
||||
|
@ -185,6 +186,8 @@ func configureSwarm(p Provisioner, swarmOptions swarm.SwarmOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
log.Debug("configuring swarm")
|
||||
|
||||
basePath := p.GetDockerOptionsDir()
|
||||
ip, err := p.GetDriver().GetIP()
|
||||
if err != nil {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/docker/machine/log"
|
||||
"github.com/docker/machine/utils"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
|
@ -46,12 +47,14 @@ const (
|
|||
|
||||
var (
|
||||
baseSSHArgs = []string{
|
||||
"-o", "PasswordAuthentication=no",
|
||||
"-o", "IdentitiesOnly=yes",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "LogLevel=quiet", // suppress "Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts."
|
||||
"-o", "ConnectionAttempts=3", // retry 3 times if SSH connection fails
|
||||
"-o", "ConnectTimeout=10", // timeout after 10 seconds
|
||||
"-t", // force tty allocation
|
||||
}
|
||||
defaultClientType SSHClientType = External
|
||||
)
|
||||
|
@ -156,7 +159,29 @@ func (client NativeClient) Output(command string) (string, error) {
|
|||
|
||||
output, err := session.CombinedOutput(command)
|
||||
|
||||
return string(output), err
|
||||
fd := int(os.Stdin.Fd())
|
||||
if err != nil {
|
||||
return string(output), err
|
||||
}
|
||||
|
||||
termWidth, termHeight, err := terminal.GetSize(fd)
|
||||
if err != nil {
|
||||
return string(output), err
|
||||
}
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
}
|
||||
|
||||
// request tty -- fixes error with hosts that use
|
||||
// "Defaults requiretty" in /etc/sudoers - I'm looking at you RedHat
|
||||
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
|
||||
return string(output), err
|
||||
}
|
||||
|
||||
return string(output), session.Run(command)
|
||||
}
|
||||
|
||||
func (client NativeClient) Shell() error {
|
||||
|
|
|
@ -121,7 +121,6 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
|
|||
for _, h := range hosts {
|
||||
if ip := net.ParseIP(h); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, h)
|
||||
}
|
||||
|
@ -131,13 +130,11 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
|
|||
tlsCert, err := tls.LoadX509KeyPair(caFile, caKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
|
||||
|
@ -153,7 +150,6 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
|
|||
certOut, err := os.Create(certFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
|
@ -162,7 +158,6 @@ func GenerateCert(hosts []string, certFile, keyFile, caFile, caKeyFile, org stri
|
|||
keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
||||
|
|
Loading…
Reference in New Issue