Merge pull request #72 from bacongobbler/off-cluster-registry

implement off-cluster registry story
This commit is contained in:
Matthew Fisher 2017-02-16 10:41:53 -08:00 коммит произвёл GitHub
Родитель 67fe9dc065 cf17773436
Коммит 1f71489e32
11 изменённых файлов: 76 добавлений и 42 удалений

Просмотреть файл

@ -87,7 +87,7 @@ compress-binary:
.PHONY: serve
serve: check-helm
helm install chart/ --name ${APP} --namespace ${APP} \
--set image.name=${IMAGE_PREFIX}/${SHORT_NAME},image.registry=${DOCKER_REGISTRY},image.tag=${IMAGE_TAG}
--set image.name=${SHORT_NAME},image.org=${IMAGE_PREFIX},image.registry=${DOCKER_REGISTRY},image.tag=${IMAGE_TAG}
.PHONY: clean
clean:

Просмотреть файл

@ -34,7 +34,8 @@ import (
const ChartTemplate = `image:
name: %s
registry: "%s:%s"
org: %s
registry: %s
tag: %s
`
@ -47,6 +48,15 @@ type APIServer struct {
HTTPServer *http.Server
Listener net.Listener
DockerClient *docker.Client
// RegistryAuth is the authorization token used to push images up to the registry.
//
// This field follows the format of the X-Registry-Auth header.
RegistryAuth string
// RegistryOrg is the organization (e.g. your DockerHub account) used to push images
// up to the registry.
RegistryOrg string
// RegistryURL is the URL of the registry (e.g. quay.io, docker.io, gcr.io)
RegistryURL string
}
// Serve starts the HTTP server, accepting all new connections.
@ -179,11 +189,11 @@ func getVersion(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
}
func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
var imagePrefix string
appName := p.ByName("id")
server := r.Context().Value("server").(*APIServer)
namespace := r.Header.Get("Kubernetes-Namespace")
logLevel := r.Header.Get("Log-Level")
registryServicePort := os.Getenv("REGISTRY_SERVICE_PORT")
// NOTE(bacongobbler): If no header was set, we default back to the default namespace.
if namespace == "" {
@ -194,10 +204,6 @@ func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
logLevel = log.GetLevel().String()
}
if registryServicePort == "" {
registryServicePort = "5000"
}
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
@ -245,8 +251,12 @@ func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
// truncate checksum to the first 40 characters (20 bytes)
// this is the equivalent of `shasum build.tar.gz | awk '{print $1}'`
tag := fmt.Sprintf("%.20x", buildContextChecksum.Sum(nil))
imageName := fmt.Sprintf("127.0.0.1:%s/%s:%s",
registryServicePort,
if server.RegistryOrg != "" {
imagePrefix = server.RegistryOrg + "/"
}
imageName := fmt.Sprintf("%s/%s%s:%s",
server.RegistryURL,
imagePrefix,
appName,
tag,
)
@ -307,9 +317,7 @@ func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
pushResp, err := server.DockerClient.ImagePush(
context.Background(),
imageName,
// assume no creds required for now
// TODO(bacongobbler): implement custom auth handling for a registry
types.ImagePushOptions{RegistryAuth: "hi"})
types.ImagePushOptions{RegistryAuth: server.RegistryAuth})
if err != nil {
conn.WriteMessage(
websocket.CloseMessage,
@ -367,8 +375,8 @@ func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
// and the version
vals := fmt.Sprintf(ChartTemplate,
appName,
os.Getenv("PROWD_SERVICE_HOST"),
os.Getenv("PROWD_SERVICE_PORT_REGISTRY"),
server.RegistryOrg,
server.RegistryURL,
tag,
)
// If a release does not exist, install it. If another error occurs during

Просмотреть файл

@ -14,10 +14,13 @@ spec:
spec:
containers:
- name: prowd
image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
image: "{{ .Values.image.registry }}/{{ .Values.image.org }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- start
- --registry-url={{ .Values.registry.url }}
- --registry-org={{ .Values.registry.org }}
- --registry-auth={{ .Values.registry.authtoken }}
{{- if .Values.debug }}
- --debug
{{- end }}
@ -34,16 +37,6 @@ spec:
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
env:
- name: "REGISTRY_SERVICE_PORT"
value: "{{ .Values.service.registry.externalPort }}"
- name: registry
image: registry:2
imagePullPolicy: Always
ports:
- containerPort: {{ .Values.service.registry.internalPort }}
hostPort: {{ .Values.service.registry.externalPort }}
name: registry
volumes:
- name: docker-socket
hostPath:

Просмотреть файл

@ -7,8 +7,5 @@ spec:
- name: http
port: {{ .Values.service.http.externalPort }}
targetPort: {{ .Values.service.http.internalPort }}
- name: registry
port: {{ .Values.service.registry.externalPort }}
targetPort: {{ .Values.service.registry.internalPort }}
selector:
app: {{ .Chart.Name }}

Просмотреть файл

@ -4,7 +4,8 @@
replicaCount: 1
image:
registry: quay.io
name: deis/prowd
org: deis
name: prowd
tag: canary
pullPolicy: Always
debug: false
@ -12,6 +13,18 @@ service:
http:
externalPort: 80
internalPort: 44135
registry:
externalPort: 5000
internalPort: 5000
registry:
url: quay.io
org: deis
# This field follows the format of Docker's X-Registry-Auth header.
#
# See https://github.com/docker/docker/blob/master/docs/api/v1.22.md#push-an-image-on-the-registry
#
# For credential-based logins, use
#
# $ echo '{"username":"jdoe","password":"secret","email":"jdoe@acme.com"}' | base64 -w 0
#
# For token-based logins, use
#
# $ echo '{"registrytoken":"9cbaf023786cd7"}' | base64 -w 0
authtoken: changeme

Просмотреть файл

@ -28,6 +28,12 @@ type startCmd struct {
dockerVersion string
// retrieve docker engine information from environment
dockerFromEnv bool
// registryAuth is the authorization token used to push images up to the registry.
registryAuth string
// registryOrg is the organization (e.g. your DockerHub account) used to push images up to the registry.
registryOrg string
// registryURL is the URL of the registry (e.g. quay.io, docker.io, gcr.io)
registryURL string
}
func newStartCmd(out io.Writer) *cobra.Command {
@ -49,6 +55,9 @@ func newStartCmd(out io.Writer) *cobra.Command {
f.StringVarP(&sc.dockerAddr, "docker-addr", "", "unix:///var/run/docker.sock", "the address the docker engine listens on")
f.StringVarP(&sc.dockerVersion, "docker-version", "", "", "the API version of the docker engine")
f.BoolVarP(&sc.dockerFromEnv, "docker-from-env", "", false, "retrieve docker engine information from environment")
f.StringVar(&sc.registryAuth, "registry-auth", "", "the authorization token used to push images up to the registry")
f.StringVar(&sc.registryOrg, "registry-org", "", "the organization (e.g. your DockerHub account) used to push images up to the registry")
f.StringVar(&sc.registryURL, "registry-url", "127.0.0.1:5000", "the URL of the registry (e.g. quay.io, docker.io, gcr.io)")
return cmd
}
@ -75,6 +84,9 @@ func (c *startCmd) run() error {
return fmt.Errorf("failed to create server at %s: %v", c.listenAddr, err)
}
server.DockerClient = dockerClient
server.RegistryAuth = c.registryAuth
server.RegistryOrg = c.registryOrg
server.RegistryURL = c.registryURL
log.Printf("server is now listening at %s", c.listenAddr)
if err = server.Serve(); err != nil {
return err

Просмотреть файл

@ -65,7 +65,7 @@ When you run `prow up`, Prow deploys your code to your Kubernetes cluster for yo
following:
- Packages your code using a `docker build`.
- Sends your code to the in-cluster Docker Registry.
- Sends your code to a Docker Registry.
- Installs (or upgrades) your chart using Helm
And when you're done with development, Prow's "first class" objects are all supported by the
@ -101,7 +101,7 @@ This is a look behind the curtain. Here's how Prow works:
- Prow uses several existing components:
- A Kubernetes cluster
- The Helm Tiller server
- An in-cluster Docker Registry
- A Docker Registry
- A directory full of "packs" for specific templates
- `prow create` reads a scaffold out of the appropriate pack, creates the necessary file system
objects, and writes some basic configuration into your chart.
@ -142,6 +142,7 @@ Inside of the `values.yaml` file, Prow configures images for your chart:
```
image:
registry: gcr.io
org: bacongobbler
name: myapp
tag: 0.1.0
```
@ -168,15 +169,16 @@ want to use:
```
image:
registry: 10.0.0.131:5000 # the address of the in-cluster registry
name: myapp # the name of the image
registry: quay.io # the address of the registry
org: bacongobbler # the organization of the image
name: myapp # the name of the image
tag: 08db751 # the release of the image in the registry
```
_How do I add an existing chart to Prow?_
Just copy (`helm fetch`) it into the `chart/` directory. You need to tweak the values file to
read from `image.regsitry`, `image.name` and `image.tag` if you want Prow to regenerate Docker
read from `image.registry`, `image.org`, `image.name` and `image.tag` if you want Prow to regenerate Docker
images for you. See above.
_How do I deploy applications to production?_

Просмотреть файл

@ -8,6 +8,7 @@ development environment for working on the Prow source code.
To compile and test Prow binaries and to build Docker images, you will need:
- [docker][]
- a [Docker Hub][] or [quay.io][quay] account
- [git][]
- [Go][] 1.7 or later, with support for compiling to `linux/amd64`
- [glide][]
@ -115,13 +116,20 @@ Client: &version.Version{SemVer:"v2.2.0", GitCommit:"fc315ab59850ddd1b9b4959c89e
Server: &version.Version{SemVer:"v2.2.0", GitCommit:"fc315ab59850ddd1b9b4959c89ef008fef5cdf89", GitTreeState:"clean"}
```
Then, install the Prow chart:
To install Prowd, edit `chart/values.yaml` and change the fields under `registry` to your
[Docker Hub][] or [quay.io][quay] account:
```
$ $EDITOR charts/values.yaml
```
Then, install the chart:
```shell
$ make serve
$ helm list # check that prowd has a helm release
NAME REVISION UPDATED STATUS CHART NAMESPACE
prowd 1 Thu Feb 16 10:18:21 2017 DEPLOYED prowd-0.1.0 prow
prow 1 Thu Feb 16 10:18:21 2017 DEPLOYED prowd-0.1.0 prow
```
## Re-deploying Your Changes

Просмотреть файл

@ -53,6 +53,7 @@ const defaultValues = `# Default values for %s.
replicaCount: 1
image:
registry: docker.io
org: library
name: nginx
tag: stable
pullPolicy: IfNotPresent
@ -109,7 +110,7 @@ spec:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
image: "{{ .Values.image.registry }}/{{ .Values.image.org }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.internalPort }}

Просмотреть файл

@ -13,7 +13,7 @@ spec:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
image: "{{ .Values.image.registry }}/{{ .Values.image.org }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.internalPort }}

Просмотреть файл

@ -15,7 +15,7 @@ spec:
spec:
containers:
- name: {{ .Chart.Name }}
image: {{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag }}
image: {{ .Values.image.registry }}/{{ .Values.image.org }}/{{ .Values.image.name }}:{{ .Values.image.tag }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 80