Compare commits

..

17 Commits
3.1.3 ... 3.2.0

Author SHA1 Message Date
Stefan Prodan
af6868a8de Merge pull request #45 from stefanprodan/prep-3.2.0
Release v3.2.0
2020-01-24 11:26:03 +02:00
stefanprodan
910e7139f9 Release v3.2.0 2020-01-24 11:06:02 +02:00
Stefan Prodan
fe65869b6b Merge pull request #43 from stefanprodan/helm-v3-e2e
e2e: Update Helm to v3 and Kubernetes to v1.17
2020-01-24 11:02:58 +02:00
Stefan Prodan
2a319d9d0d Merge pull request #44 from hiddeco/unhealthy-unready
Add `--unhealthy` and `--unready` flags
2020-01-23 22:42:29 +02:00
Hidde Beydals
48402eff7e Add --unhealthy and --unready flags to chart 2020-01-23 21:06:30 +01:00
Hidde Beydals
15600cc7d3 Lowercase all flag descriptions 2020-01-23 21:06:30 +01:00
Hidde Beydals
ed2a774e10 Add --unhealthy and --unready flags
Depending on the flag set, the healthy or ready state is never
reached.
2020-01-23 21:06:22 +01:00
stefanprodan
1d590c07cb e2e: Update Helm to v3 and Kubernetes to v1.17 2020-01-22 13:16:03 +02:00
stefanprodan
948de81ed3 Update manifests to v3.1.5 2019-12-26 15:45:17 +02:00
stefanprodan
78658c0311 Release v3.1.5 cuddle edition 2019-11-07 00:31:49 +02:00
stefanprodan
7b6f11780a Rename GitHub workflow for kustomize testing 2019-11-04 09:59:11 +02:00
stefanprodan
d65044ff2e Release v3.1.4 2019-11-04 09:22:36 +02:00
Stefan Prodan
18c63ad7f7 Merge pull request #42 from mumoshu/h2c
feat: Add H2C support
2019-11-04 09:16:12 +02:00
Yusuke Kuoka
a8260081d9 Add h2c.enabled to chart for toggling H2C upgrading support 2019-11-04 14:17:10 +09:00
Yusuke Kuoka
0ff49e5057 feat: Add H2C support
`podinfo --h2c` allows upgrading a HTTP/1.1 connection to HTTP/2 Cleartext.

This allows `podinfo` to be used in e.g. a H2C load-test like `echo "GET http://localhost:9898/status/200" | vegeta -h2c`, or a H2C connectivity test like done with `curl -v http2 http://localhost:9898/status/200`.

I have manually verified this to work by running `curl -v --http2` on macOS and seeing the H2C upgrade happens onl when `-h2c` is provided to `podinfo`.

Without `-h2c`:

```
$ curl -v --http2 localhost:9898/status/200
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9898 (#0)
> GET /status/200 HTTP/1.1
> Host: localhost:9898
> User-Agent: curl/7.54.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Mon, 04 Nov 2019 04:58:01 GMT
< Content-Length: 19
<
{
  "status": 200
* Connection #0 to host localhost left intact
}
```

With `-h2c`:

```
$ curl -v --http2 localhost:9898/status/200
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9898 (#0)
> GET /status/200 HTTP/1.1
> Host: localhost:9898
> User-Agent: curl/7.54.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
< HTTP/1.1 101 Switching Protocols
< Connection: Upgrade
< Upgrade: h2c
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
< content-type: application/json; charset=utf-8
< x-content-type-options: nosniff
< content-length: 19
< date: Mon, 04 Nov 2019 04:58:28 GMT
<
{
  "status": 200
* Connection #0 to host localhost left intact
}
`
2019-11-04 14:10:50 +09:00
Stefan Prodan
79cfe56484 Merge pull request #41 from stefanprodan/gh-actions
Add GitHub workflow for manifests validation
2019-10-23 17:35:53 +03:00
stefanprodan
7e36892e26 Add GitHub workflow for manifests validation
- validate kustomize build with kubeval strict mode
- deny containers with latest image tag
- deny deployments and services without app label selector
- warn if deployments have no prometheus pod annotations
2019-10-23 17:10:21 +03:00
21 changed files with 189 additions and 46 deletions

View File

@@ -11,7 +11,7 @@ jobs:
name: Start Kubernetes Kind cluster
command: e2e/bootstrap.sh
- run:
name: Install podinfo with Helm
name: Install podinfo with Helm v3
command: e2e/install.sh
- run:
name: Run Helm tests

51
.github/policy/kubernetes.rego vendored Normal file
View File

@@ -0,0 +1,51 @@
package kubernetes
name = input.metadata.name
kind = input.kind
is_service {
input.kind = "Service"
}
is_deployment {
input.kind = "Deployment"
}
is_pod {
input.kind = "Pod"
}
split_image(image) = [image, "latest"] {
not contains(image, ":")
}
split_image(image) = [image_name, tag] {
[image_name, tag] = split(image, ":")
}
pod_containers(pod) = all_containers {
keys = {"containers", "initContainers"}
all_containers = [c | keys[k]; c = pod.spec[k][_]]
}
containers[container] {
pods[pod]
all_containers = pod_containers(pod)
container = all_containers[_]
}
containers[container] {
all_containers = pod_containers(input)
container = all_containers[_]
}
pods[pod] {
is_deployment
pod = input.spec.template
}
pods[pod] {
is_pod
pod = input
}

43
.github/policy/rules.rego vendored Normal file
View File

@@ -0,0 +1,43 @@
package main
import data.kubernetes
name = input.metadata.name
# Deny containers with latest image tag
deny[msg] {
kubernetes.containers[container]
[image_name, "latest"] = kubernetes.split_image(container.image)
msg = sprintf("%s in the %s %s has an image %s, using the latest tag", [container.name, kubernetes.kind, kubernetes.name, image_name])
}
# Deny services without app label selector
service_labels {
input.spec.selector["app"]
}
deny[msg] {
kubernetes.is_service
not service_labels
msg = sprintf("Service %s should set app label selector", [name])
}
# Deny deployments without app label selector
match_labels {
input.spec.selector.matchLabels["app"]
}
deny[msg] {
kubernetes.is_deployment
not match_labels
msg = sprintf("Service %s should set app label selector", [name])
}
# Warn if deployments have no prometheus pod annotations
annotations {
input.spec.template.metadata.annotations["prometheus.io/scrape"]
input.spec.template.metadata.annotations["prometheus.io/port"]
}
warn[msg] {
kubernetes.is_deployment
not annotations
msg = sprintf("Deployment %s should set prometheus.io/scrape and prometheus.io/port pod annotations", [name])
}

17
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
on: [push, pull_request]
name: test
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: kubeval
uses: stefanprodan/kube-tools@v1
with:
command: |
kustomize build ./kustomize | kubeval --strict
- name: conftest
uses: stefanprodan/kube-tools@v1
with:
command: |
kustomize build ./kustomize | conftest test -p .github/policy -

View File

@@ -8,11 +8,12 @@ DOCKER_REPOSITORY:=stefanprodan
DOCKER_IMAGE_NAME:=$(DOCKER_REPOSITORY)/$(NAME)
GIT_COMMIT:=$(shell git describe --dirty --always)
VERSION:=$(shell grep 'VERSION' pkg/version/version.go | awk '{ print $$4 }' | tr -d '"')
EXTRA_RUN_ARGS?=
run:
GO111MODULE=on go run -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" cmd/podinfo/* \
--level=debug --grpc-port=9999 --backend-url=https://httpbin.org/status/401 --backend-url=https://httpbin.org/status/500 \
--ui-logo=https://media.giphy.com/media/l0ExbNdlJFGRphMR2/giphy.gif
--ui-logo=https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif --ui-color=#34577c $(EXTRA_RUN_ARGS)
test:
GO111MODULE=on go test -v -race ./...

View File

@@ -1,6 +1,7 @@
# podinfo
[![CircleCI](https://circleci.com/gh/stefanprodan/podinfo.svg?style=svg)](https://circleci.com/gh/stefanprodan/podinfo)
[![conftest](https://github.com/stefanprodan/podinfo/workflows/test/badge.svg)](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/test.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/stefanprodan/podinfo)](https://goreportcard.com/report/github.com/stefanprodan/podinfo)
[![Docker Pulls](https://img.shields.io/docker/pulls/stefanprodan/podinfo)](https://hub.docker.com/r/stefanprodan/podinfo)
@@ -20,6 +21,7 @@ Specifications:
* Swagger docs
* Helm and Kustomize installers
* End-to-End testing with Kubernetes Kind and Helm
* Kustomize testing with GitHub Actions and Open Policy Agent
Web API:
@@ -51,7 +53,7 @@ gRPC API:
Web UI:
![podinfo-ui](https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/screens/podinfo-ui.png)
![podinfo-ui](https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/screens/podinfo-ui-v3.png)
To access the Swagger UI open `<podinfo-host>/swagger/index.html` in a browser.
@@ -67,20 +69,20 @@ To access the Swagger UI open `<podinfo-host>/swagger/index.html` in a browser.
Helm:
```bash
helm repo add sp https://stefanprodan.github.io/podinfo
helm repo add podinfo https://stefanprodan.github.io/podinfo
helm upgrade --install --wait frontend \
--namespace test \
--set replicaCount=2 \
--set backend=http://backend-podinfo:9898/echo \
sp/podinfo
podinfo/podinfo
helm test frontend --cleanup
helm upgrade --install --wait backend \
--namespace test \
--set hpa.enabled=true \
sp/podinfo
podinfo/podinfo
```
Kustomize:

View File

@@ -1,6 +1,6 @@
apiVersion: v1
version: 3.1.3
appVersion: 3.1.3
version: 3.2.0
appVersion: 3.2.0
name: podinfo
engine: gotpl
description: Podinfo Helm chart for Kubernetes

View File

@@ -36,6 +36,8 @@ Parameter | Description | Default
`backends` | echo backend URL array | None
`faults.delay` | random HTTP response delays between 0 and 5 seconds | `false`
`faults.error` | 1/3 chances of a random HTTP response error | `false`
`faults.unhealthy` | when set, the healthy state is never reached | `false`
`faults.unready` | when set, the ready state is never reached | `false`
`hpa.enabled` | enables HPA | `false`
`hpa.cpu` | target CPU usage per pod | None
`hpa.memory` | target memory usage per pod | None

View File

@@ -54,6 +54,15 @@ spec:
- --level={{ .Values.logLevel }}
- --random-delay={{ .Values.faults.delay }}
- --random-error={{ .Values.faults.error }}
{{- if .Values.faults.unhealthy }}
- --unhealthy
{{- end }}
{{- if .Values.faults.unready }}
- --unready
{{- end }}
{{- if .Values.h2c.enabled }}
- --h2c
{{- end }}
env:
{{- if .Values.ui.message }}
- name: PODINFO_UI_MESSAGE

View File

@@ -5,7 +5,7 @@ metadata:
name: {{ template "podinfo.fullname" . }}
spec:
scaleTargetRef:
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
name: {{ template "podinfo.fullname" . }}
minReplicas: {{ .Values.replicaCount }}

View File

@@ -6,17 +6,22 @@ backend: #http://backend-podinfo:9898/echo
backends: []
ui:
color: "cyan"
color: "#34577c"
message: ""
logo: ""
faults:
delay: false
error: false
unhealthy: false
unready: false
h2c:
enabled: false
image:
repository: stefanprodan/podinfo
tag: 3.1.3
tag: 3.2.0
pullPolicy: IfNotPresent
service:

View File

@@ -39,9 +39,12 @@ func main() {
fs.String("ui-logo", "", "UI logo")
fs.String("ui-color", "cyan", "UI color")
fs.String("ui-message", fmt.Sprintf("greetings from podinfo v%v", version.VERSION), "UI message")
fs.Bool("h2c", false, "allow upgrading to H2C")
fs.Bool("random-delay", false, "between 0 and 5 seconds random delay")
fs.Bool("random-error", false, "1/3 chances of a random response error")
fs.Int("stress-cpu", 0, "Number of CPU cores with 100 load")
fs.Bool("unhealthy", false, "when set, healthy state is never reached")
fs.Bool("unready", false, "when set, ready state is never reached")
fs.Int("stress-cpu", 0, "number of CPU cores with 100 load")
fs.Int("stress-memory", 0, "MB of data to load into memory")
versionFlag := fs.BoolP("version", "v", false, "get version number")
@@ -65,7 +68,7 @@ func main() {
viper.RegisterAlias("backendUrl", "backend-url")
hostname, _ := os.Hostname()
viper.SetDefault("jwt-secret", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
viper.SetDefault("ui-logo", "https://d33wubrfki0l68.cloudfront.net/33a12d8be0bc50be4738443101616e968c7afb8f/cba76/images/scalable.png")
viper.SetDefault("ui-logo", "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif")
viper.Set("hostname", hostname)
viper.Set("version", version.VERSION)
viper.Set("revision", version.REVISION)

View File

@@ -7,11 +7,11 @@ The e2e testing infrastructure is powered by CircleCI and [Kubernetes Kind](http
* download go modules
* run unit tests
* build container
* install kubectl, helm and Kubernetes Kind CLIs
* install kubectl, Helm v3 and Kubernetes Kind CLIs
* create local Kubernetes cluster with kind
* deploy Tiller on the local cluster
* load podinfo image onto the local cluster
* deploy podinfo with Helm
* set the podinfo image to the locally built one
* run Helm tests
```yaml

View File

@@ -3,7 +3,7 @@
set -o errexit
REPO_ROOT=$(git rev-parse --show-toplevel)
KIND_VERSION=v0.5.1
KIND_VERSION=v0.7.0
if [[ "$1" ]]; then
KIND_VERSION=$1
@@ -22,13 +22,5 @@ sudo mv kind /usr/local/bin/kind
echo ">>> Creating kind cluster"
kind create cluster --wait 5m
export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl get pods --all-namespaces
echo ">>> Installing Helm"
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
echo '>>> Installing Tiller'
kubectl --namespace kube-system create sa tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
helm init --service-account tiller --upgrade --wait
echo ">>> Installing Helm v3"
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

View File

@@ -3,7 +3,6 @@
set -o errexit
REPO_ROOT=$(git rev-parse --show-toplevel)
export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
echo '>>> Loading image in Kind'
kind load docker-image test/podinfo:latest

View File

@@ -2,15 +2,11 @@
set -o errexit
REPO_ROOT=$(git rev-parse --show-toplevel)
export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
function finish {
echo '>>> Test logs'
kubectl logs -l app=podinfo
}
trap finish EXIT
echo '>>> Testing'
echo '>>> Start integration tests'
helm test podinfo

2
go.mod
View File

@@ -47,6 +47,6 @@ require (
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
google.golang.org/grpc v1.23.0
)

View File

@@ -25,7 +25,7 @@ spec:
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:3.1.3
image: stefanprodan/podinfo:3.2.0
imagePullPolicy: IfNotPresent
ports:
- name: http
@@ -48,7 +48,7 @@ spec:
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: cyan
value: "#34577c"
livenessProbe:
exec:
command:

View File

@@ -4,6 +4,9 @@ import (
"context"
"fmt"
"github.com/swaggo/swag"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"net/http"
_ "net/http/pprof"
"os"
@@ -59,8 +62,11 @@ type Config struct {
Port string `mapstructure:"port"`
PortMetrics int `mapstructure:"port-metrics"`
Hostname string `mapstructure:"hostname"`
H2C bool `mapstructure:"h2c"`
RandomDelay bool `mapstructure:"random-delay"`
RandomError bool `mapstructure:"random-error"`
Unhealthy bool `mapstructure:"unhealthy"`
Unready bool `mapstructure:"unready"`
JWTSecret string `mapstructure:"jwt-secret"`
}
@@ -141,12 +147,19 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
s.registerHandlers()
s.registerMiddlewares()
var handler http.Handler
if s.config.H2C {
handler = h2c.NewHandler(s.router, &http2.Server{})
} else {
handler = s.router
}
srv := &http.Server{
Addr: ":" + s.config.Port,
WriteTimeout: s.config.HttpServerTimeout,
ReadTimeout: s.config.HttpServerTimeout,
IdleTimeout: 2 * s.config.HttpServerTimeout,
Handler: s.router,
Handler: handler,
}
//s.printRoutes()
@@ -170,8 +183,12 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
}()
// signal Kubernetes the server is ready to receive traffic
atomic.StoreInt32(&healthy, 1)
atomic.StoreInt32(&ready, 1)
if !s.config.Unhealthy {
atomic.StoreInt32(&healthy, 1)
}
if !s.config.Unready {
atomic.StoreInt32(&ready, 1)
}
// wait for SIGTERM or SIGINT
<-stopCh

View File

@@ -1,4 +1,4 @@
package version
var VERSION = "3.1.3"
var VERSION = "3.2.0"
var REVISION = "unknown"

View File

@@ -10,8 +10,11 @@
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<style>
[v-cloak] {
display: none;
}
display: none;
}
.v-application .v-parallax {
height: 100vh !important;
}
</style>
</head>
<body>
@@ -19,14 +22,14 @@
<v-app dark>
<v-content>
<section>
<v-parallax id="parallax-hero" src="https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png" :class="info.color">
<v-parallax id="parallax-hero" :style="cuddleStyle" src="https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png">
<v-layout
column
align-center
justify-center
class="white--text"
>
<img :src="info.logo" alt="kubernetes" height="200">
<img :src="info.logo" height="350">
<h1 class="white--text mb-2 display-1 text-xs-center">${ info.message }</h1>
<div class="subheading mb-3 text-xs-center">Served by <b>${ info.hostname }</b></div>
<v-btn
@@ -86,11 +89,11 @@
tlColor1: 'grey',
tlName2: '',
tlColor2: 'grey',
cuddleStyle: {
backgroundColor: '#34577c'
},
}
},
mounted: function() {
document.getElementById('parallax-hero').style.height = '100vh'
},
created: function() {
this.getInfo();
this.timer = setInterval(this.getInfo, 3000)
@@ -109,6 +112,9 @@
}
self.info = data
self.info.color = data.color
self.cuddleStyle = {
backgroundColor: data.color
}
self.info.logo = data.logo
document.title = data.hostname
let verColor = (parseInt(data.version.split('.').reverse()[0], 10) % 2 === 0)