mirror of
https://github.com/golang/go.git
synced 2025-05-30 19:52:53 +00:00
cmd/tip: move tip.golang.org from App Engine to Kubernetes on GKE
Change-Id: I52ca7eaca98de27bd920ae01086b3f7724819738 Reviewed-on: https://go-review.googlesource.com/37754 Reviewed-by: Chris Broadfoot <cbro@golang.org>
This commit is contained in:
parent
767744efe2
commit
03d3934baf
@ -1,13 +1,15 @@
|
|||||||
FROM golang:1.6
|
FROM golang:1.8
|
||||||
|
|
||||||
RUN apt-get update && apt-get install --no-install-recommends -y -q build-essential git
|
RUN apt-get update && apt-get install --no-install-recommends -y -q build-essential git
|
||||||
|
|
||||||
# golang puts its go install here (weird but true)
|
# golang puts its go install here (weird but true)
|
||||||
ENV GOROOT_BOOTSTRAP /usr/local/go
|
ENV GOROOT_BOOTSTRAP /usr/local/go
|
||||||
|
|
||||||
|
RUN go get -d golang.org/x/crypto/acme/autocert
|
||||||
|
|
||||||
# golang sets GOPATH=/go
|
# golang sets GOPATH=/go
|
||||||
ADD . /go/src/tip
|
ADD . /go/src/tip
|
||||||
RUN go install tip
|
RUN go install tip
|
||||||
ENTRYPOINT ["/go/bin/tip"]
|
ENTRYPOINT ["/go/bin/tip"]
|
||||||
# Kubernetes expects us to listen on port 8080
|
# App Engine expects us to listen on port 8080
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
15
cmd/tip/Makefile
Normal file
15
cmd/tip/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
VERSION=v1
|
||||||
|
|
||||||
|
docker-prod: Dockerfile
|
||||||
|
docker build -f Dockerfile --tag=gcr.io/symbolic-datum-552/tip:$(VERSION) .
|
||||||
|
docker-dev: Dockerfile
|
||||||
|
docker build -f Dockerfile --tag=gcr.io/go-dashboard-dev/tip:$(VERSION) .
|
||||||
|
|
||||||
|
push-prod: docker-prod
|
||||||
|
gcloud docker push -- gcr.io/symbolic-datum-552/tip:$(VERSION)
|
||||||
|
push-dev: docker-dev
|
||||||
|
gcloud docker push -- gcr.io/go-dashboard-dev/tip:$(VERSION)
|
@ -1,7 +1,11 @@
|
|||||||
|
============================================================
|
||||||
|
Old instructions, only valid for talks.golang.org:
|
||||||
|
============================================================
|
||||||
|
|
||||||
1. Deploy the app.
|
1. Deploy the app.
|
||||||
|
|
||||||
To deploy tip.golang.org:
|
To deploy tip.golang.org:
|
||||||
$ gcloud --project golang-org app deploy --no-promote godoc.yaml
|
(See Kubernetes instruction below.)
|
||||||
|
|
||||||
To deploy talks.golang.org:
|
To deploy talks.golang.org:
|
||||||
$ gcloud --project golang-org app deploy --no-promote talks.yaml
|
$ gcloud --project golang-org app deploy --no-promote talks.yaml
|
||||||
@ -12,3 +16,18 @@
|
|||||||
https://console.developers.google.com/appengine/versions?project=golang-org&moduleId=tip
|
https://console.developers.google.com/appengine/versions?project=golang-org&moduleId=tip
|
||||||
|
|
||||||
4. Clean up any old versions (they continue to use at least one instance).
|
4. Clean up any old versions (they continue to use at least one instance).
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
New Kubernetes instructions, for tip.golang.org:
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
Kubernetes instructions:
|
||||||
|
|
||||||
|
* build & push images (see Makefile for helpers)
|
||||||
|
* create/update resources:
|
||||||
|
- kubectl create -f tip-rc.yaml
|
||||||
|
- kubectl create -f tip-service.yaml
|
||||||
|
|
||||||
|
TODO(bradfitz): flesh out these instructions as I gain experience
|
||||||
|
with updating this over time. Also: move talks.golang.org to GKE too?
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ type godocBuilder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b godocBuilder) Signature(heads map[string]string) string {
|
func (b godocBuilder) Signature(heads map[string]string) string {
|
||||||
return heads["go"] + "-" + heads["tools"]
|
return fmt.Sprintf("go=%v/tools=%v", heads["go"], heads["tools"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b godocBuilder) Init(dir, hostport string, heads map[string]string) (*exec.Cmd, error) {
|
func (b godocBuilder) Init(dir, hostport string, heads map[string]string) (*exec.Cmd, error) {
|
||||||
|
40
cmd/tip/tip-rc.yaml
Normal file
40
cmd/tip/tip-rc.yaml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ReplicationController
|
||||||
|
metadata:
|
||||||
|
name: tipgodoc-v1
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
app: tipgodoc
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: tipgodoc
|
||||||
|
labels:
|
||||||
|
app: tipgodoc
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: cache-volume
|
||||||
|
emptyDir: {}
|
||||||
|
containers:
|
||||||
|
- name: gitmirror
|
||||||
|
image: gcr.io/symbolic-datum-552/tip:v1
|
||||||
|
imagePullPolicy: Always
|
||||||
|
command: ["/go/bin/tip", "--autocert=tip.golang.org"]
|
||||||
|
env:
|
||||||
|
- name: TMPDIR
|
||||||
|
value: /build
|
||||||
|
- name: TIP_BUILDER
|
||||||
|
value: godoc
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /build
|
||||||
|
name: cache-volume
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
- containerPort: 443
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "1"
|
||||||
|
memory: "2Gi"
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: "4Gi"
|
16
cmd/tip/tip-service.yaml
Normal file
16
cmd/tip/tip-service.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: tipgodoc
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 8080
|
||||||
|
name: http
|
||||||
|
- port: 443
|
||||||
|
targetPort: 443
|
||||||
|
name: https
|
||||||
|
selector:
|
||||||
|
app: tipgodoc
|
||||||
|
type: LoadBalancer
|
||||||
|
loadBalancerIP: 130.211.180.236
|
@ -8,8 +8,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -22,6 +24,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/acme/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -30,7 +34,15 @@ const (
|
|||||||
startTimeout = 10 * time.Minute
|
startTimeout = 10 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var startTime = time.Now()
|
||||||
|
|
||||||
|
var (
|
||||||
|
autoCertDomain = flag.String("autocert", "", "if non-empty, listen on port 443 and serve a LetsEncrypt cert for this hostname")
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
const k = "TIP_BUILDER"
|
const k = "TIP_BUILDER"
|
||||||
var b Builder
|
var b Builder
|
||||||
switch os.Getenv(k) {
|
switch os.Getenv(k) {
|
||||||
@ -47,9 +59,28 @@ func main() {
|
|||||||
http.Handle("/", httpsOnlyHandler{p})
|
http.Handle("/", httpsOnlyHandler{p})
|
||||||
http.HandleFunc("/_ah/health", p.serveHealthCheck)
|
http.HandleFunc("/_ah/health", p.serveHealthCheck)
|
||||||
|
|
||||||
log.Print("Starting up")
|
log.Printf("Starting up tip server for builder %q", os.Getenv(k))
|
||||||
|
|
||||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
errc := make(chan error)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
errc <- http.ListenAndServe(":8080", nil)
|
||||||
|
}()
|
||||||
|
if *autoCertDomain != "" {
|
||||||
|
log.Printf("Listening on port 443 with LetsEncrypt support on domain %q", *autoCertDomain)
|
||||||
|
m := autocert.Manager{
|
||||||
|
Prompt: autocert.AcceptTOS,
|
||||||
|
HostPolicy: autocert.HostWhitelist(*autoCertDomain),
|
||||||
|
}
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: ":https",
|
||||||
|
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
errc <- s.ListenAndServeTLS("", "")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if err := <-errc; err != nil {
|
||||||
p.stop()
|
p.stop()
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -98,14 +129,17 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (p *Proxy) serveStatus(w http.ResponseWriter, r *http.Request) {
|
func (p *Proxy) serveStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
fmt.Fprintf(w, "side=%v\ncurrent=%v\nerror=%v\n", p.side, p.cur, p.err)
|
fmt.Fprintf(w, "side=%v\ncurrent=%v\nerror=%v\nuptime=%v\n", p.side, p.cur, p.err, int(time.Since(startTime).Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) serveHealthCheck(w http.ResponseWriter, r *http.Request) {
|
func (p *Proxy) serveHealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
// NOTE: Status 502, 503, 504 are the only status codes that signify an unhealthy app.
|
|
||||||
// So long as this handler returns one of those codes, this instance will not be sent any requests.
|
// NOTE: (App Engine only; not GKE) Status 502, 503, 504 are
|
||||||
|
// the only status codes that signify an unhealthy app. So
|
||||||
|
// long as this handler returns one of those codes, this
|
||||||
|
// instance will not be sent any requests.
|
||||||
if p.proxy == nil {
|
if p.proxy == nil {
|
||||||
log.Printf("Health check: not ready")
|
log.Printf("Health check: not ready")
|
||||||
http.Error(w, "Not ready", http.StatusServiceUnavailable)
|
http.Error(w, "Not ready", http.StatusServiceUnavailable)
|
||||||
@ -266,11 +300,13 @@ func checkout(repo, hash, path string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var timeoutClient = &http.Client{Timeout: 10 * time.Second}
|
||||||
|
|
||||||
// gerritMetaMap returns the map from repo name (e.g. "go") to its
|
// gerritMetaMap returns the map from repo name (e.g. "go") to its
|
||||||
// latest master hash.
|
// latest master hash.
|
||||||
// The returned map is nil on any transient error.
|
// The returned map is nil on any transient error.
|
||||||
func gerritMetaMap() map[string]string {
|
func gerritMetaMap() map[string]string {
|
||||||
res, err := http.Get(metaURL)
|
res, err := timeoutClient.Get(metaURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -309,7 +345,7 @@ func gerritMetaMap() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getOK(url string) (body []byte, err error) {
|
func getOK(url string) (body []byte, err error) {
|
||||||
res, err := http.Get(url)
|
res, err := timeoutClient.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user