Browse code

Allow specifing docker registry per build

Maciej Szulik authored on 2014/09/26 01:20:44
Showing 17 changed files
... ...
@@ -51,15 +51,15 @@ Remember, you can pass a URL to `-c` when using the `kube` command, so you can [
51 51
 
52 52
 ### Docker registry
53 53
 
54
-OpenShift builds allow pushing built images into docker registry. Currently we only support one registry per OpenShift installation.
55
-Still you can use either private [docker registry](https://github.com/docker/docker-registry) or the [official docker hub](https://hub.docker.com/).
54
+OpenShift builds allow pushing built images into docker registry, for details see [our API](#API).
55
+You can use either private [docker registry](https://github.com/docker/docker-registry) or the
56
+[official docker hub](https://hub.docker.com/). If the two are available private will be favored.
56 57
 
57 58
 **Private docker registry**
58 59
 
59 60
 To setup private docker registry you can either follow the steps [here](https://github.com/docker/docker-registry#quick-start)
60 61
 or use [simple-ruby-app example](https://github.com/openshift/origin/blob/master/examples/simple-ruby-app)
61
-to host one inside OpenShift. Afterwards you need to pass `DOCKER_REGISTRY` environment variable to `openshift start`
62
-command, specifying the address of your registry, e.g. `DOCKER_REGISTRY=localhost:5000`.
62
+to host one inside OpenShift. Now all you need to do is to specify your repository in `buildConfig`.
63 63
 
64 64
 **Docker Hub**
65 65
 
... ...
@@ -4,6 +4,7 @@
4 4
     "desiredInput": {
5 5
         "builderImage": "openshift/ruby-19-centos",
6 6
         "imageTag": "test-ruby-app",
7
+        "registry": "localhost:5000",
7 8
         "sourceURI": "git://github.com/pmorie/simple-ruby",
8 9
         "type": "sti"
9 10
     },
... ...
@@ -1,4 +1,4 @@
1
-<!DOCTYPE HTML><html><head><title>OpenShift 3 API documentation</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=generator content="https://github.com/kevinrenskers/raml2html 1.0.3"><link rel=stylesheet href=http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css><link rel=stylesheet href=http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.1/styles/default.min.css><script type=text/javascript src=http://code.jquery.com/jquery-1.11.0.min.js></script><script type=text/javascript src=http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js></script><script type=text/javascript src=http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.1/highlight.min.js></script><script type=text/javascript>
1
+<!DOCTYPE HTML><html><head><title>OpenShift 3 API documentation</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=generator content="https://github.com/kevinrenskers/raml2html 1.0.4"><link rel=stylesheet href=http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css><link rel=stylesheet href=http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.1/styles/default.min.css><script type=text/javascript src=http://code.jquery.com/jquery-1.11.0.min.js></script><script type=text/javascript src=http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js></script><script type=text/javascript src=http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.1/highlight.min.js></script><script type=text/javascript>
2 2
         $(document).ready(function() {
3 3
             $('.page-header pre code, .top-resource-description pre code').each(function(i, block) {
4 4
                 hljs.highlightBlock(block);
... ...
@@ -191,6 +191,7 @@
191 191
     "desiredInput": {
192 192
         "builderImage": "openshift/ruby-19-centos",
193 193
         "imageTag": "test-ruby-app",
194
+        "registry": "localhost:5000",
194 195
         "sourceURI": "git://github.com/pmorie/simple-ruby",
195 196
         "type": "sti"
196 197
     },
... ...
@@ -204,6 +205,7 @@
204 204
     "desiredInput": {
205 205
         "builderImage": "openshift/ruby-19-centos",
206 206
         "imageTag": "test-ruby-app",
207
+        "registry": "localhost:5000",
207 208
         "sourceURI": "git://github.com/pmorie/simple-ruby",
208 209
         "type": "sti"
209 210
     },
... ...
@@ -2,10 +2,11 @@
2 2
     "id": "build100",
3 3
     "desiredInput":
4 4
     {
5
-        "type": "docker",
5
+        "type":      "docker",
6 6
         "sourceURI": "git://github.com/openshift/ruby-hello-world.git",
7
-        "imageTag":     "openshift/origin-ruby-sample",
7
+        "imageTag":  "openshift/origin-ruby-sample",
8
+        "registry":  "localhost:5000",
8 9
     },
9
- 
10
+
10 11
     "secret": "secret101"
11 12
 }
12 13
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-{
2
-   "zen":"Encourage flow.",
3
-   "hook":{
4
-      "url":"https://api.github.com/repos/anonUser/anonRepo/hooks/2896466",
5
-      "test_url":"https://api.github.com/repos/anonUser/anonRepo/hooks/2896466/test",
6
-      "id":2896466,
7
-      "name":"web",
8
-      "active":true,
9
-      "events":[
10
-         "push"
11
-      ],
12
-      "config":{
13
-         "secret":"",
14
-         "url":"http://example.com/gitwebhook",
15
-         "content_type":"json",
16
-         "insecure_ssl":"0"
17
-      },
18
-      "last_response":{
19
-         "code":null,
20
-         "status":"unused",
21
-         "message":null
22
-      },
23
-      "updated_at":"2014-08-28T14:25:47Z",
24
-      "created_at":"2014-08-28T14:25:47Z"
25
-   },
26
-   "hook_id":2896466
27
-}
... ...
@@ -4,6 +4,8 @@ echo "Killing openshift all-in-one server"
4 4
 killall openshift
5 5
 echo "Cleaning up openshift etcd content"
6 6
 rm -rf openshift.local.etcd
7
+echo "Cleaning up openshift etcd volumes"
8
+rm -rf openshift.local.volumes
7 9
 echo "Killing all docker containers on host"
8 10
 docker kill `docker ps --no-trunc -q`
9 11
 
... ...
@@ -15,11 +15,9 @@ rm -rf openshift.local.etcd
15 15
 
16 16
 
17 17
 # Start the OpenShift all-in-one server
18
-# (starts a kubernetes master and minion as well as providing the
19
-# origin REST api)
20
-# DOCKER_REGISTRY refers to the private Docker registry running inside a pod in OpenShift.
18
+# (starts a kubernetes master and minion as well as providing the origin REST api)
21 19
 echo "Launching openshift all-in-one server"
22
-DOCKER_REGISTRY=localhost:5000 $openshift start --listenAddr="0.0.0.0:8080" &> logs/openshift.log &
20
+$openshift start --listenAddr="0.0.0.0:8080" &> logs/openshift.log &
23 21
 
24 22
 sleep 5
25 23
 
... ...
@@ -35,6 +35,9 @@ type BuildInput struct {
35 35
 	// ImageTag is the tag to give to the image resulting from the build
36 36
 	ImageTag string `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
37 37
 
38
+	// Registry to push the result image to
39
+	Registry string `json:"registry",omitempty" yaml:"registry,omitempty"`
40
+
38 41
 	// BuilderImage is the image used to execute the build when running STI builds
39 42
 	BuilderImage string `json:"builderImage,omitempty" yaml:"builderImage,omitempty"`
40 43
 }
... ...
@@ -35,6 +35,9 @@ type BuildInput struct {
35 35
 	// ImageTag is the tag to give to the image resulting from the build
36 36
 	ImageTag string `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
37 37
 
38
+	// Registry to push the result image to
39
+	Registry string `json:"registry",omitempty" yaml:"registry,omitempty"`
40
+
38 41
 	// BuilderImage is the image used to execute the build when running STI builds
39 42
 	BuilderImage string `json:"builderImage,omitempty" yaml:"builderImage,omitempty"`
40 43
 }
... ...
@@ -18,7 +18,7 @@ import (
18 18
 // BuildJobStrategy represents a strategy for executing a build by
19 19
 // creating a pod definition that will execute the build
20 20
 type BuildJobStrategy interface {
21
-	CreateBuildPod(build *api.Build, dockerImage string) (*kubeapi.Pod, error)
21
+	CreateBuildPod(build *api.Build) (*kubeapi.Pod, error)
22 22
 }
23 23
 
24 24
 // BuildController watches build resources and manages their state
... ...
@@ -26,7 +26,6 @@ type BuildController struct {
26 26
 	osClient        osclient.Interface
27 27
 	kubeClient      kubeclient.Interface
28 28
 	buildStrategies map[api.BuildType]BuildJobStrategy
29
-	dockerRegistry  string
30 29
 	timeout         int
31 30
 }
32 31
 
... ...
@@ -34,17 +33,14 @@ type BuildController struct {
34 34
 func NewBuildController(kc kubeclient.Interface,
35 35
 	oc osclient.Interface,
36 36
 	strategies map[api.BuildType]BuildJobStrategy,
37
-	registry string,
38 37
 	timeout int) *BuildController {
39 38
 
40
-	glog.Infof("Creating build controller with dockerRegistry=%s, timeout=%d",
41
-		registry, timeout)
39
+	glog.Infof("Creating build controller with timeout=%d", timeout)
42 40
 
43 41
 	bc := &BuildController{
44 42
 		kubeClient:      kc,
45 43
 		osClient:        oc,
46 44
 		buildStrategies: strategies,
47
-		dockerRegistry:  registry,
48 45
 		timeout:         timeout,
49 46
 	}
50 47
 	return bc
... ...
@@ -107,7 +103,7 @@ func (bc *BuildController) synchronize(build *api.Build) (api.BuildStatus, error
107 107
 			return api.BuildError, fmt.Errorf("No build type for %s", build.Input.Type)
108 108
 		}
109 109
 
110
-		podSpec, err := buildStrategy.CreateBuildPod(build, bc.dockerRegistry)
110
+		podSpec, err := buildStrategy.CreateBuildPod(build)
111 111
 		if err != nil {
112 112
 			glog.Errorf("Unable to create build pod: %v", err)
113 113
 			return api.BuildFailed, err
... ...
@@ -33,7 +33,7 @@ func (_ *errOsClient) UpdateBuild(build *api.Build) (*api.Build, error) {
33 33
 
34 34
 type okStrategy struct{}
35 35
 
36
-func (_ *okStrategy) CreateBuildPod(build *api.Build, dockerRegistry string) (*kubeapi.Pod, error) {
36
+func (_ *okStrategy) CreateBuildPod(build *api.Build) (*kubeapi.Pod, error) {
37 37
 	return &kubeapi.Pod{}, nil
38 38
 }
39 39
 
... ...
@@ -17,7 +17,7 @@ func NewDockerBuildStrategy(dockerBuilderImage string) *DockerBuildStrategy {
17 17
 
18 18
 // CreateBuildPod creates the pod to be used for the Docker build
19 19
 // TODO: Make the Pod definition configurable
20
-func (bs *DockerBuildStrategy) CreateBuildPod(build *buildapi.Build, dockerRegistry string) (*api.Pod, error) {
20
+func (bs *DockerBuildStrategy) CreateBuildPod(build *buildapi.Build) (*api.Pod, error) {
21 21
 	pod := &api.Pod{
22 22
 		JSONBase: api.JSONBase{
23 23
 			ID: build.PodID,
... ...
@@ -32,7 +32,7 @@ func (bs *DockerBuildStrategy) CreateBuildPod(build *buildapi.Build, dockerRegis
32 32
 						Env: []api.EnvVar{
33 33
 							{Name: "BUILD_TAG", Value: build.Input.ImageTag},
34 34
 							{Name: "DOCKER_CONTEXT_URL", Value: build.Input.SourceURI},
35
-							{Name: "DOCKER_REGISTRY", Value: dockerRegistry},
35
+							{Name: "DOCKER_REGISTRY", Value: build.Input.Registry},
36 36
 						},
37 37
 					},
38 38
 				},
... ...
@@ -8,10 +8,9 @@ import (
8 8
 )
9 9
 
10 10
 func TestDockerCreateBuildPod(t *testing.T) {
11
-	const dockerRegistry = "docker-test-registry"
12 11
 	strategy := NewDockerBuildStrategy("docker-test-image")
13 12
 	expected := mockDockerBuild()
14
-	actual, _ := strategy.CreateBuildPod(expected, dockerRegistry)
13
+	actual, _ := strategy.CreateBuildPod(expected)
15 14
 
16 15
 	if actual.JSONBase.ID != expected.PodID {
17 16
 		t.Errorf("Expected %s, but got %s!", expected.PodID, actual.JSONBase.ID)
... ...
@@ -36,8 +35,8 @@ func TestDockerCreateBuildPod(t *testing.T) {
36 36
 	if e := container.Env[1]; e.Name != "DOCKER_CONTEXT_URL" && e.Value != expected.Input.SourceURI {
37 37
 		t.Errorf("Expected %s, got %s:%s!", expected.Input.ImageTag, e.Name, e.Value)
38 38
 	}
39
-	if e := container.Env[2]; e.Name != "DOCKER_REGISTRY" && e.Value != dockerRegistry {
40
-		t.Errorf("Expected %s got %s:%s!", dockerRegistry, e.Name, e.Value)
39
+	if e := container.Env[2]; e.Name != "DOCKER_REGISTRY" && e.Value != expected.Input.Registry {
40
+		t.Errorf("Expected %s got %s:%s!", expected.Input.Registry, e.Name, e.Value)
41 41
 	}
42 42
 }
43 43
 
... ...
@@ -50,6 +49,7 @@ func mockDockerBuild() *api.Build {
50 50
 			Type:      api.DockerBuildType,
51 51
 			SourceURI: "http://my.build.com/the/dockerbuild/Dockerfile",
52 52
 			ImageTag:  "repository/dockerBuild",
53
+			Registry:  "docker-registry",
53 54
 		},
54 55
 		Status: api.BuildNew,
55 56
 		PodID:  "-the-pod-id",
... ...
@@ -33,7 +33,7 @@ func NewSTIBuildStrategy(stiBuilderImage string, tc TempDirectoryCreator) *STIBu
33 33
 
34 34
 // CreateBuildPod creates a pod that will execute the STI build
35 35
 // TODO: Make the Pod definition configurable
36
-func (bs *STIBuildStrategy) CreateBuildPod(build *buildapi.Build, dockerRegistry string) (*api.Pod, error) {
36
+func (bs *STIBuildStrategy) CreateBuildPod(build *buildapi.Build) (*api.Pod, error) {
37 37
 	pod := &api.Pod{
38 38
 		JSONBase: api.JSONBase{
39 39
 			ID: build.PodID,
... ...
@@ -47,7 +47,7 @@ func (bs *STIBuildStrategy) CreateBuildPod(build *buildapi.Build, dockerRegistry
47 47
 						Image: bs.stiBuilderImage,
48 48
 						Env: []api.EnvVar{
49 49
 							{Name: "BUILD_TAG", Value: build.Input.ImageTag},
50
-							{Name: "DOCKER_REGISTRY", Value: dockerRegistry},
50
+							{Name: "DOCKER_REGISTRY", Value: build.Input.Registry},
51 51
 							{Name: "SOURCE_URI", Value: build.Input.SourceURI},
52 52
 							{Name: "SOURCE_REF", Value: build.Input.SourceRef},
53 53
 							{Name: "BUILDER_IMAGE", Value: build.Input.BuilderImage},
... ...
@@ -14,10 +14,9 @@ func (t *FakeTempDirCreator) CreateTempDirectory() (string, error) {
14 14
 }
15 15
 
16 16
 func TestSTICreateBuildPod(t *testing.T) {
17
-	const dockerRegistry = "sti-test-registry"
18 17
 	strategy := NewSTIBuildStrategy("sti-test-image", &FakeTempDirCreator{})
19 18
 	expected := mockSTIBuild()
20
-	actual, _ := strategy.CreateBuildPod(expected, dockerRegistry)
19
+	actual, _ := strategy.CreateBuildPod(expected)
21 20
 
22 21
 	if actual.JSONBase.ID != expected.PodID {
23 22
 		t.Errorf("Expected %s, but got %s!", expected.PodID, actual.JSONBase.ID)
... ...
@@ -39,8 +38,8 @@ func TestSTICreateBuildPod(t *testing.T) {
39 39
 	if e := container.Env[0]; e.Name != "BUILD_TAG" || e.Value != expected.Input.ImageTag {
40 40
 		t.Errorf("Expected %s, got %s:%s!", expected.Input.ImageTag, e.Name, e.Value)
41 41
 	}
42
-	if e := container.Env[1]; e.Name != "DOCKER_REGISTRY" || e.Value != dockerRegistry {
43
-		t.Errorf("Expected %s got %s:%s!", dockerRegistry, e.Name, e.Value)
42
+	if e := container.Env[1]; e.Name != "DOCKER_REGISTRY" || e.Value != expected.Input.Registry {
43
+		t.Errorf("Expected %s got %s:%s!", expected.Input.Registry, e.Name, e.Value)
44 44
 	}
45 45
 	if e := container.Env[2]; e.Name != "SOURCE_URI" || e.Value != expected.Input.SourceURI {
46 46
 		t.Errorf("Expected %s got %s:%s!", expected.Input.SourceURI, e.Name, e.Value)
... ...
@@ -62,6 +61,7 @@ func mockSTIBuild() *api.Build {
62 62
 			Type:      api.STIBuildType,
63 63
 			SourceURI: "http://my.build.com/the/stibuild/Dockerfile",
64 64
 			ImageTag:  "repository/stiBuild",
65
+			Registry:  "docker-registry",
65 66
 		},
66 67
 		Status: api.BuildNew,
67 68
 		PodID:  "-the-pod-id",
... ...
@@ -32,11 +32,15 @@ func setupDockerSocket(podSpec *api.Pod) {
32 32
 
33 33
 // setupDockerConfig configures the path to .dockercfg which contains registry credentials
34 34
 func setupDockerConfig(podSpec *api.Pod) {
35
+	dockerConfig := path.Join(os.Getenv("HOME"), ".dockercfg")
36
+	if _, err := os.Stat(dockerConfig); os.IsNotExist(err) {
37
+		return
38
+	}
35 39
 	dockerConfigVolume := api.Volume{
36 40
 		Name: "docker-cfg",
37 41
 		Source: &api.VolumeSource{
38 42
 			HostDirectory: &api.HostDirectory{
39
-				Path: path.Join(os.Getenv("HOME"), ".dockercfg"),
43
+				Path: dockerConfig,
40 44
 			},
41 45
 		},
42 46
 	}
... ...
@@ -403,14 +403,13 @@ func (c *config) runBuildController() {
403 403
 	// initialize build controller
404 404
 	dockerBuilderImage := env("OPENSHIFT_DOCKER_BUILDER_IMAGE", "openshift/docker-builder")
405 405
 	stiBuilderImage := env("OPENSHIFT_STI_BUILDER_IMAGE", "openshift/sti-builder")
406
-	dockerRegistry := env("DOCKER_REGISTRY", "")
407 406
 
408 407
 	buildStrategies := map[buildapi.BuildType]build.BuildJobStrategy{
409 408
 		buildapi.DockerBuildType: strategy.NewDockerBuildStrategy(dockerBuilderImage),
410 409
 		buildapi.STIBuildType:    strategy.NewSTIBuildStrategy(stiBuilderImage, strategy.STITempDirectoryCreator),
411 410
 	}
412 411
 
413
-	buildController := build.NewBuildController(kubeClient, osClient, buildStrategies, dockerRegistry, 1200)
412
+	buildController := build.NewBuildController(kubeClient, osClient, buildStrategies, 1200)
414 413
 	buildController.Run(10 * time.Second)
415 414
 }
416 415