Compare commits

...

134 Commits

Author SHA1 Message Date
Stefan Prodan
dc27269a47 Merge pull request #26 from stefanprodan/prep-v2.0.0
Release v2.0.0
2019-08-06 17:17:45 +03:00
stefanprodan
eeb1d2b674 Publish podinfo CLI to GitHub releases 2019-08-06 17:03:09 +03:00
stefanprodan
6da79daa96 Add release command 2019-08-06 16:58:35 +03:00
stefanprodan
34aef54f20 Release v2 2019-08-06 16:53:38 +03:00
stefanprodan
dc96b15dac Add badges 2019-08-06 16:53:02 +03:00
stefanprodan
64ff737dca Add CircleCI release workflow 2019-08-06 16:44:05 +03:00
Stefan Prodan
3c76b54c80 Merge pull request #25 from stefanprodan/v2
Prepare v2 release
2019-08-06 16:41:11 +03:00
stefanprodan
fc5a9797e8 Add guides to readme 2019-08-06 16:33:20 +03:00
stefanprodan
fb183d897b Publish Helm chart to GH Pages 2019-08-06 16:14:07 +03:00
stefanprodan
67711cf150 Add Kustomize and Helm install to readme 2019-08-06 15:59:58 +03:00
stefanprodan
0ca7c25d68 Set version with make 2019-08-06 15:59:39 +03:00
stefanprodan
eb0ad32655 Add Kustomize installer 2019-08-06 15:59:03 +03:00
stefanprodan
f9ce51da4b Push container on release 2019-08-06 15:32:37 +03:00
stefanprodan
045246c324 Cleanup make 2019-08-06 15:06:27 +03:00
stefanprodan
9bd14c1ba7 Use go proxy and modules 2019-08-06 15:06:16 +03:00
stefanprodan
6f59e98bec Add timeline to UI 2019-08-06 15:05:37 +03:00
stefanprodan
c287ab7daf Rename imports and use go modules 2019-08-06 15:05:15 +03:00
stefanprodan
e2efee0bdf Remove docs and build dirs 2019-08-06 12:14:09 +03:00
stefanprodan
6c8a85a5ab Release v1.8.0 2019-08-05 10:00:23 +03:00
Stefan Prodan
c9dc78f29c Merge pull request #22 from imduffy15/master
Add delayed chunk endpoint
2019-08-05 09:20:27 +03:00
Ian Duffy
6a9b0253ac Update README.md 2019-08-04 10:06:20 +01:00
Ian Duffy
198211e20b Add delayed chunk endpoint
Adds an endpoint that does chunk based encoding. The endpoint just stalls
and eventually returns the stall time.

Similar to the delay endpoint but in a chunked maner.

Fixed up the metrics interceptor to wrap ResponseWriter correctly too.
2019-08-04 00:34:12 +01:00
stefanprodan
e1ca9e227d Remove the middle htlm section 2019-07-26 01:15:47 +03:00
stefanprodan
4fc593f42c Bump version to 1.7.1 2019-07-26 01:02:01 +03:00
stefanprodan
18af1ea3a6 Merge remote-tracking branch 'origin/master' 2019-07-26 00:53:35 +03:00
stefanprodan
2e9917a6b9 Bump version to 1.7.0 2019-07-26 00:53:22 +03:00
Stefan Prodan
bf00d07b17 Merge pull request #20 from grampelberg/master
Upgrade to vuetify 2.x
2019-07-26 00:45:06 +03:00
grampelberg
aab8e464e8 Upgrade to vuetify 2.x 2019-07-25 13:31:12 -07:00
stefanprodan
1475a2da00 Release charts 2019-06-15 18:33:10 +03:00
Stefan Prodan
44f588dd4c Merge pull request #19 from stefanprodan/metrics-port
Add option to run the metrics exporter on a different port
2019-06-15 17:14:01 +03:00
stefanprodan
951d82abb9 Add option to run the metrics exporter on a different port
Add port-metrics flag, when specified the Prometheus /metrics endpoint will be exposed on that port.
2019-06-15 17:07:34 +03:00
Stefan Prodan
3301f6f8d4 Merge pull request #18 from stefanprodan/fix-helm-test
Fix storage tests
2019-04-19 12:45:53 +03:00
stefanprodan
0339d3beb0 Fix storage tests 2019-04-19 12:44:58 +03:00
Stefan Prodan
d1b77c97b8 Merge pull request #17 from mumoshu/patch-1
fix(doc): Update README about read/write endpoints
2019-04-19 11:02:02 +03:00
KUOKA Yusuke
bfa3aaf9ac fix(doc): Update README about read/write endpoints
I was following https://github.com/stefanprodan/k8s-podinfo/blob/master/docs/1-deploy.md#using-the-helm-chart and `helm test` failed.

The cause seemed like changes in two endpoints. `POST /write` seems to have changed to `POST /store`, and `GET /read/{hash}` to `GET /store/{hash}`. Here's the fix according to my observation :)
2019-04-19 16:39:09 +09:00
stefanprodan
43df2d19c6 Bump version to 1.5.1 2019-03-25 12:16:20 +02:00
stefanprodan
7181351c89 Bump version to 1.5.0 2019-03-25 12:08:37 +02:00
Stefan Prodan
1c3bf10de2 Merge pull request #16 from luxas/ui-pathprefix
Fix the UI XHRs when the webserver is mounted at a non-root URL
2019-03-25 11:28:51 +02:00
Lucas Käldström
c28c11d4a5 Release v1.4.4 2019-03-25 11:22:38 +02:00
Lucas Käldström
5c2f9a19d6 Make the UI perform XHRs relative to its own path 2019-03-25 11:21:33 +02:00
Stefan Prodan
7d5200a78a Merge pull request #15 from stefanprodan/fix-port
Add port validation
2019-03-21 21:06:10 +02:00
stefanprodan
66b8948473 Bump version to 1.4.3 2019-03-21 20:57:07 +02:00
stefanprodan
db04ce117b Add port validation 2019-03-21 20:43:02 +02:00
stefanprodan
5142c39a8e Add arm64 and amd64 Drone pipelines 2019-02-08 01:07:15 +02:00
stefanprodan
001486ac0a Push ARMv7 image with Drone 2019-02-08 00:43:53 +02:00
stefanprodan
ed553135b2 Set Drone platform to arm 2019-02-08 00:32:15 +02:00
stefanprodan
c21c24b2fd Build master with Drone 2019-02-08 00:25:55 +02:00
stefanprodan
4dbbfa9239 Rename Drone pipeline 2019-02-08 00:12:04 +02:00
stefanprodan
bc8ff9b412 Build ARM image with Drone on Scaleway 2019-02-08 00:06:23 +02:00
stefanprodan
cdf9b06b86 Upgrade golang GitHub action to 1.11 2018-12-20 17:52:56 +02:00
stefanprodan
431ab9e19e Disable Travis Kubernetes in Docker (kind) 2018-12-20 15:57:09 +02:00
stefanprodan
1273d3745e Run podinfo local image on Travis Kubernetes in Docker 2018-12-20 15:36:58 +02:00
stefanprodan
caa49b96aa Run podinfo on Travis Kubernetes in Docker 2018-12-20 15:22:06 +02:00
stefanprodan
319e444ddf Fix kubectl perm for Travis Kubernetes in Docker 2018-12-20 15:12:39 +02:00
stefanprodan
0529fff9aa Test Travis Kubernetes in Docker 2018-12-20 15:07:58 +02:00
stefanprodan
0fc239aaca Test Kubernetes in Docker 2018-12-20 14:56:21 +02:00
stefanprodan
f0b19b63e9 Add sem ver release to TravisCI docs 2018-12-20 10:22:49 +02:00
stefanprodan
d10ba4ac43 Release 1.4.2 2018-12-20 09:57:19 +02:00
stefanprodan
7a2dca6798 Add TravisCI and Quay docs 2018-12-20 09:56:17 +02:00
stefanprodan
62ccb1b67e run go 1.11 fmt 2018-12-20 09:41:08 +02:00
stefanprodan
579284c775 Bootstrap travis in podcli code init 2018-12-20 09:33:55 +02:00
Stefan Prodan
a4948e16dd Remove labels and update deployment to API apps/v1 2018-12-04 16:26:44 +07:00
Stefan Prodan
995dcb5042 Publish chart v1.4.1
- set probes timeout to 5s (fix for GKE containerd)
2018-12-04 16:15:56 +07:00
stefanprodan
cbf1d671df Bump version to 1.4.1 2018-11-28 12:11:18 +02:00
stefanprodan
f6987a0a09 Publish v1.4 Helm chart 2018-11-28 12:01:05 +02:00
Stefan Prodan
ea93f3ed9f Bump version to 1.4.0 2018-11-28 11:45:41 +02:00
Stefan Prodan
2fc253a7c7 Merge pull request #8 from guyfedwards/blue-green-flagger
Set background colour based on version
2018-11-28 11:37:03 +02:00
guyfedwards
c83e19a217 set color based on primary/canary workload
sets the bg color as blue for primary and green for canary workloads
2018-11-27 17:41:41 +00:00
Stefan Prodan
a9a1252a22 Add brew install cmd for podcli 2018-11-07 14:58:37 +02:00
Stefan Prodan
046a9a4852 Add version to code init commit message 2018-10-27 12:19:54 +03:00
Stefan Prodan
4d78abdad8 Prep for v1.3.2 release 2018-10-27 12:19:15 +03:00
Stefan Prodan
f8b32fa130 Release ngrok helm chart v0.2.0 2018-10-27 12:02:46 +03:00
Stefan Prodan
a30fb535de Merge pull request #7 from tdickman/subdomain-support
Add ngrok subdomain support
2018-10-27 12:00:12 +03:00
Stefan Prodan
8d662334a2 Update GitHub actions docs 2018-10-27 11:59:24 +03:00
Stefan Prodan
4ed9271783 Release v1.3.1 2018-10-27 11:50:14 +03:00
Stefan Prodan
97157694be Add logs to Docker build GitHub action 2018-10-27 11:48:32 +03:00
Stefan Prodan
bf92728234 Generate Github actions CI pipeline
- add custom Dockerfile
- use GitHub actions env vars as docker build args
- remove .gh from Makefile and Dockerfile in destination project
2018-10-27 11:41:52 +03:00
Tom Dickman
bd31f8b23e Add ngrok subdomain support 2018-10-26 14:06:37 -05:00
Stefan Prodan
f7c8061ac0 Bump version in GitHub Actions docs 2018-10-26 19:07:00 +03:00
Stefan Prodan
943f4e26ab Release v1.3.1 2018-10-26 19:05:17 +03:00
Stefan Prodan
f44909ef77 Add golang tools GitHub Action 2018-10-26 18:23:02 +03:00
Stefan Prodan
1af24bd3cd Run gofmt 2018-10-26 18:20:54 +03:00
Stefan Prodan
14ef95dac6 Release v1.3.0 2018-10-26 15:32:22 +03:00
Stefan Prodan
08a26cef24 Add GitHub Actions docs 2018-10-26 15:30:36 +03:00
Stefan Prodan
8013c0bed0 Merge pull request #6 from stefanprodan/test
Add code init command and GitHub actions
2018-10-26 15:08:05 +03:00
Stefan Prodan
6aa4303e08 Bump version to 1.3.0 2018-10-26 15:02:39 +03:00
Stefan Prodan
f34fbacf13 Add git push to code init command 2018-10-26 15:01:48 +03:00
Stefan Prodan
b7701f6ae7 Don't reload page if version changed 2018-10-26 15:01:24 +03:00
Stefan Prodan
d3208cd8ac Add custom GitHub action for docker tag and push
- if the push refers a branch the docker tag will be branch-sha
- if the push refers a git tag the docker tag will be th git tag
2018-10-26 14:29:16 +03:00
Stefan Prodan
7d4c89d965 Add GitHub release workflow 2018-10-26 13:06:49 +03:00
Stefan Prodan
3b5ac61680 Remove chart from code init 2018-10-26 13:06:21 +03:00
Stefan Prodan
e8e2ac2b34 Run unit tests in docker multi-stage build 2018-10-26 12:37:13 +03:00
Stefan Prodan
ef571a9b1b Add initialize podinfo code repo command 2018-10-26 12:09:21 +03:00
Stefan Prodan
3d9cabcea4 Add GitHub workflow for branch test, build and push 2018-10-26 12:08:59 +03:00
Stefan Prodan
ae4120a24e Add go-getter pkg 2018-10-26 12:08:01 +03:00
Stefan Prodan
97d36bd8bb Release v1.2.1
- wait for the readiness probe to remove the endpoint from the LB before entering HTTP server graceful shutdown
2018-09-25 12:10:46 +03:00
Stefan Prodan
18a22d1b94 Add shutdown delay (wait for the readiness probe) 2018-09-25 12:01:01 +03:00
Stefan Prodan
083de34465 Fix podinfo-istio chart health checks 2018-09-19 13:16:25 +03:00
Stefan Prodan
64b85dc30d Move Istio docs to the istio-gke repo 2018-09-18 14:54:30 +03:00
Stefan Prodan
fed964e223 Expose Istio Grafana 2018-09-17 18:34:34 +03:00
Stefan Prodan
efb6a76242 Mention Istio Gateway reload cert issue 2018-09-17 13:58:38 +03:00
Stefan Prodan
fb199b72a1 Split GKE and Could DNS setup 2018-09-17 12:51:01 +03:00
Stefan Prodan
ce117e1706 Add Could DNS verify commands 2018-09-16 20:47:34 +03:00
Stefan Prodan
23e67f9923 Remove istio sub domain 2018-09-16 14:29:41 +03:00
Stefan Prodan
30b030a685 Add CloudDNS CNAME record 2018-09-16 14:07:04 +03:00
Stefan Prodan
0fe4a7a3a9 Add GKE, CloudDNS and Helm setup steps 2018-09-16 13:48:58 +03:00
Stefan Prodan
982063ab9b Resize Istio cert-manager diagram 2018-09-16 12:49:48 +03:00
Stefan Prodan
c3256bd18f Add Istio cert-manager diagram 2018-09-16 12:43:08 +03:00
Stefan Prodan
d947fc5b2c Add OpenFaaS Istio port-forward commands 2018-09-14 16:49:41 +03:00
Stefan Prodan
dc6d64137d Add OpenFaaS Istio intro 2018-09-14 13:25:20 +03:00
Stefan Prodan
f3c1ee7dbc Add OpenFaaS Istio canary diagram 2018-09-14 12:04:58 +03:00
Stefan Prodan
6b6dd86fea Add OpenFaaS Istio diagram 2018-09-14 11:13:09 +03:00
Stefan Prodan
02e5f233d0 Release v1.2.0 2018-09-11 22:18:58 +03:00
Stefan Prodan
b89f46ac04 Add websocket client command to CLI 2018-09-11 22:14:59 +03:00
Stefan Prodan
59cd692141 Add websocket echo handler 2018-09-11 22:13:54 +03:00
Stefan Prodan
bcd61428d1 Import gorilla/websocket 2018-09-11 22:12:37 +03:00
Stefan Prodan
f8ec9c0947 Fix multi-arch docker push 2018-09-11 18:04:13 +03:00
Stefan Prodan
6c98fbf1f4 Add JWT token issue and validate handlers 2018-09-10 11:36:11 +03:00
Stefan Prodan
54f6d9f74d Add env handler 2018-09-10 01:29:49 +03:00
Stefan Prodan
1d35304d9d OpenfaaS canary deployments 2018-09-09 16:38:37 +03:00
Stefan Prodan
457a56f71a Publish podinfo CLI to GitHub with goreleaser 2018-09-09 12:38:23 +03:00
Stefan Prodan
fbcab6cf56 Upgrade to go 1.11 and alpine 3.8 2018-09-09 12:37:58 +03:00
Stefan Prodan
0126282669 add goreleaser 2018-09-08 19:05:37 +03:00
Stefan Prodan
ff1fb39f43 Release v1.1.0
- add podinfo CLI to Quay docker image
- use podinfo CLI for health checks (Istio mTLS support)
2018-09-08 11:38:48 +03:00
Stefan Prodan
84f0e1c9e2 Add CLI check certificate 2018-09-07 15:26:07 +03:00
Stefan Prodan
3eb4cc90f9 Add CLI to Quay docker image 2018-09-07 14:55:24 +03:00
Stefan Prodan
b6c3d36bde Add CLI check tcp command 2018-09-07 14:54:55 +03:00
Stefan Prodan
a8a85e6aae Add CLI version cmd 2018-09-07 14:54:35 +03:00
Stefan Prodan
79b2d784bf Add OpenFaaS Istio guide WIP 2018-09-07 13:38:39 +03:00
Stefan Prodan
bfd35f6cc0 Make health checks compatible with Istio mTLS 2018-09-07 13:38:18 +03:00
Stefan Prodan
f1775ba090 Add podinfo CLI WIP 2018-09-07 13:37:40 +03:00
Stefan Prodan
7a2d59de8e Add OpenFaaS Istio mTLS and policies 2018-09-05 15:38:53 +03:00
Stefan Prodan
8191871761 Add Istio A/B test dashboard 2018-09-05 15:38:24 +03:00
Stefan Prodan
36bb719b1c Bump version to 1.0.1 2018-08-27 16:26:30 +01:00
851 changed files with 1938 additions and 280656 deletions

View File

@@ -1,38 +1,52 @@
version: 2
version: 2.1
jobs:
build:
push-helm-charts:
docker:
- image: errordeveloper/skaffold:66cc263ef18f107adce245b8fc622a8ea46385f2
- image: circleci/golang:1.12
steps:
- checkout
- setup_remote_docker: {docker_layer_caching: true}
- run:
name: Run unit tests and build the image with Skaffold
command: skaffold build --profile=test
deploy:
docker:
- image: errordeveloper/skaffold:66cc263ef18f107adce245b8fc622a8ea46385f2
steps:
- checkout
- setup_remote_docker: {docker_layer_caching: true}
name: Install kubectl
command: sudo curl -L https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl && sudo chmod +x /usr/local/bin/kubectl
- run:
name: Build and push the image to the registry with Skaffold
name: Install helm
command: sudo curl -L https://storage.googleapis.com/kubernetes-helm/helm-v2.14.2-linux-amd64.tar.gz | tar xz && sudo mv linux-amd64/helm /bin/helm && sudo rm -rf linux-amd64
- run:
name: Initialize helm
command: helm init --client-only --kubeconfig=$HOME/.kube/kubeconfig
- run:
name: Lint charts
command: |
if [[ -z "${CIRCLE_PULL_REQUEST}" ]] && [[ "${CIRCLE_PROJECT_USERNAME}" = "stefanprodan" ]] ; then
echo $REGISTRY_PASSWORD | docker login --username $REGISTRY_USERNAME --password-stdin
skaffold build --profile=production
helm lint ./charts/*
- run:
name: Package charts
command: |
mkdir $HOME/charts
helm package ./charts/* --destination $HOME/charts
- run:
name: Publish charts
command: |
if echo "${CIRCLE_TAG}" | grep -Eq "[0-9]+(\.[0-9]+)*(-[a-z]+)?$"; then
REPOSITORY="https://stefanprodan:${GITHUB_TOKEN}@github.com/stefanprodan/podinfo.git"
git config user.email stefanprodan@users.noreply.github.com
git config user.name stefanprodan
git remote set-url origin ${REPOSITORY}
git checkout gh-pages
mv -f $HOME/charts/*.tgz .
helm repo index . --url https://stefanprodan.github.io/podinfo
git add .
git commit -m "Publish Helm charts v${CIRCLE_TAG}"
git push origin gh-pages
else
echo "Do not push image"
echo "Not a release! Skip charts publish"
fi
workflows:
version: 2
main:
release:
jobs:
- build
- deploy:
requires: [build]
- push-helm-charts:
filters:
branches: {only: [master]}
branches:
ignore: /.*/
tags:
ignore: /^chart.*/

View File

@@ -1,9 +0,0 @@
docs
deploy
charts
cloudbuild.yaml
skaffold.yaml
.gitignore
.travis.yml
LICENSE
README.md

2
.gitignore vendored
View File

@@ -18,3 +18,5 @@
release/
build/
gcloud/
dist/
bin/

16
.goreleaser.yml Normal file
View File

@@ -0,0 +1,16 @@
builds:
- main: ./cmd/podcli
binary: podcli
ldflags: -s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION={{.Commit}}
goos:
- windows
- darwin
- linux
goarch:
- amd64
env:
- CGO_ENABLED=0
archives:
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files:
- none*

View File

@@ -2,7 +2,7 @@ sudo: required
language: go
go:
- 1.9.x
- 1.12.x
services:
- docker
@@ -12,32 +12,21 @@ addons:
packages:
- docker-ce
before_install:
- make dep
# - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
# - mkdir -p .bin; mv ./kubectl .bin/kubectl && chmod +x .bin/kubectl
# - export PATH="$TRAVIS_BUILD_DIR/.bin:$PATH"
# - wget https://cdn.rawgit.com/Mirantis/kubeadm-dind-cluster/master/fixed/dind-cluster-v1.8.sh && chmod +x dind-cluster-v1.8.sh && ./dind-cluster-v1.8.sh up
# - export PATH="$HOME/.kubeadm-dind-cluster:$PATH"
script:
- make test
- make build docker-build
# - kubectl get nodes
# - kubectl run podinfo --image=podinfo:latest --port=9898
# - sleep 5
# - kubectl get pods
- make build-container
after_success:
- if [ -z "$DOCKER_USER" ]; then
echo "PR build, skipping Docker Hub push";
- if [ -z "$TRAVIS_TAG" ]; then
echo "Not a release, skipping container push";
else
echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin;
make docker-push;
fi
- if [ -z "$QUAY_USER" ]; then
echo "PR build, skipping Quay push";
else
echo $QUAY_PASS | docker login -u $QUAY_USER --password-stdin quay.io;
make quay-push;
make push-container;
fi
deploy:
- provider: script
skip_cleanup: true
script: curl -sL http://git.io/goreleaser | bash
on:
tags: true

View File

@@ -1,4 +1,26 @@
FROM alpine:3.7
FROM golang:1.12 as builder
RUN mkdir -p /podinfo/
WORKDIR /podinfo
COPY . .
RUN GOPROXY=https://proxy.golang.org go mod download
RUN go test -v -race ./...
RUN GIT_COMMIT=$(git rev-list -1 HEAD) && \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${GIT_COMMIT}" \
-a -o bin/podinfo cmd/podinfo/*
RUN GIT_COMMIT=$(git rev-list -1 HEAD) && \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${GIT_COMMIT}" \
-a -o bin/podcli cmd/podcli/*
FROM alpine:3.10
RUN addgroup -S app \
&& adduser -S -g app app \
@@ -6,9 +28,10 @@ RUN addgroup -S app \
curl openssl netcat-openbsd
WORKDIR /home/app
COPY ./ui ./ui
ADD podinfo .
COPY --from=builder /podinfo/bin/podinfo .
COPY --from=builder /podinfo/bin/podcli /usr/local/bin/podcli
COPY ./ui ./ui
RUN chown -R app:app ./
USER app

View File

@@ -1,6 +0,0 @@
FROM alpine:3.7
COPY ./ui ./ui
ADD podinfo /podinfo
CMD ["./podinfo"]

View File

@@ -1,32 +0,0 @@
FROM golang:1.9 as builder
RUN mkdir -p /go/src/github.com/stefanprodan/k8s-podinfo/
WORKDIR /go/src/github.com/stefanprodan/k8s-podinfo
COPY . .
RUN go test $(go list ./... | grep -v integration | grep -v /vendor/ | grep -v /template/) -cover
RUN gofmt -l -d $(find . -type f -name '*.go' -not -path "./vendor/*") && \
GIT_COMMIT=$(git rev-list -1 HEAD) && \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w \
-X github.com/stefanprodan/k8s-podinfo/pkg/version.REVISION=${GIT_COMMIT}" \
-a -installsuffix cgo -o podinfo ./cmd/podinfo
FROM alpine:3.7
RUN addgroup -S app \
&& adduser -S -g app app \
&& apk --no-cache add \
curl openssl netcat-openbsd
WORKDIR /home/app
COPY --from=builder /go/src/github.com/stefanprodan/k8s-podinfo/podinfo .
COPY ./ui ./ui
RUN chown -R app:app ./
USER app
CMD ["./podinfo"]

199
Gopkg.lock generated
View File

@@ -1,199 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/beorn7/perks"
packages = ["quantile"]
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
name = "github.com/fsnotify/fsnotify"
packages = ["."]
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
version = "v1.4.7"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
name = "github.com/gorilla/context"
packages = ["."]
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
branch = "master"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
"json/parser",
"json/scanner",
"json/token"
]
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
[[projects]]
name = "github.com/magiconair/properties"
packages = ["."]
revision = "c2353362d570a7bfa228149c62842019201cfb71"
version = "v1.8.0"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
version = "v1.2.0"
[[projects]]
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/promhttp"
]
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_model"
packages = ["go"]
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
[[projects]]
branch = "master"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
[[projects]]
branch = "master"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs"
]
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
[[projects]]
name = "github.com/spf13/afero"
packages = [
".",
"mem"
]
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
version = "v1.1.1"
[[projects]]
name = "github.com/spf13/cast"
packages = ["."]
revision = "8965335b8c7107321228e3e3702cab9832751bac"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/spf13/jwalterweatherman"
packages = ["."]
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
[[projects]]
name = "github.com/spf13/pflag"
packages = ["."]
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
version = "v1.0.2"
[[projects]]
name = "github.com/spf13/viper"
packages = ["."]
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
version = "v1.1.0"
[[projects]]
name = "go.uber.org/atomic"
packages = ["."]
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
version = "v1.3.2"
[[projects]]
name = "go.uber.org/multierr"
packages = ["."]
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0"
[[projects]]
name = "go.uber.org/zap"
packages = [
".",
"buffer",
"internal/bufferpool",
"internal/color",
"internal/exit",
"zapcore"
]
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
version = "v1.9.1"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "1a700e749ce29638d0bbcb531cce1094ea096bd3"
[[projects]]
name = "golang.org/x/text"
packages = [
"internal/gen",
"internal/triegen",
"internal/ucd",
"transform",
"unicode/cldr",
"unicode/norm"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "95fe64936946a78f8261f1054187eb37c9766694640a68915416d8ba9f192b6a"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,27 +0,0 @@
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.8.0"
[[constraint]]
name = "github.com/gorilla/mux"
version = "v1.6.2"
[[constraint]]
name = "go.uber.org/zap"
version = "v1.9.1"
[[override]]
name = "github.com/fsnotify/fsnotify"
version = "1.2.9"
[[constraint]]
name = "github.com/spf13/pflag"
version = "v1.0.2"
[[constraint]]
name = "github.com/spf13/viper"
version = "v1.1.0"
[prune]
go-tests = true
unused-packages = true

134
Makefile
View File

@@ -1,114 +1,46 @@
# Makefile for releasing Alpine multi-arch Docker images
# Makefile for releasing podinfo
#
# The release version is controlled from pkg/version
EMPTY:=
SPACE:=$(EMPTY) $(EMPTY)
COMMA:=$(EMPTY),$(EMPTY)
TAG?=latest
NAME:=podinfo
DOCKER_REPOSITORY:=stefanprodan
DOCKER_IMAGE_NAME:=$(DOCKER_REPOSITORY)/$(NAME)
GITREPO:=github.com/stefanprodan/k8s-podinfo
GITCOMMIT:=$(shell git describe --dirty --always)
VERSION:=$(shell grep 'VERSION' pkg/version/version.go | awk '{ print $$4 }' | tr -d '"')
LINUX_ARCH:=arm arm64 ppc64le s390x amd64
PLATFORMS:=$(subst $(SPACE),$(COMMA),$(foreach arch,$(LINUX_ARCH),linux/$(arch)))
.PHONY: build
build:
@echo Cleaning old builds
@rm -rf build && mkdir build
@echo Building: linux/$(LINUX_ARCH) $(VERSION) ;\
for arch in $(LINUX_ARCH); do \
mkdir -p build/linux/$$arch && CGO_ENABLED=0 GOOS=linux GOARCH=$$arch go build -ldflags="-s -w -X $(GITREPO)/pkg/version.REVISION=$(GITCOMMIT)" -o build/linux/$$arch/$(NAME) ./cmd/$(NAME) ;\
cp -r ui/ build/linux/$$arch/ui;\
done
run:
GO111MODULE=on go run cmd/podinfo/*
.PHONY: tar
tar: build
@echo Cleaning old releases
@rm -rf release && mkdir release
for arch in $(LINUX_ARCH); do \
tar -zcf release/$(NAME)_$(VERSION)_linux_$$arch.tgz -C build/linux/$$arch $(NAME) ;\
done
.PHONY: docker-build
docker-build: tar
# Steps:
# 1. Copy appropriate podinfo binary to build/docker/linux/<arch>
# 2. Copy Dockerfile to build/docker/linux/<arch>
# 3. Replace base image from alpine:latest to <arch>/alpine:latest
# 4. Comment RUN in Dockerfile
# <arch>:
# arm: arm32v6
# arm64: arm64v8
rm -rf build/docker
@for arch in $(LINUX_ARCH); do \
mkdir -p build/docker/linux/$$arch ;\
tar -xzf release/$(NAME)_$(VERSION)_linux_$$arch.tgz -C build/docker/linux/$$arch ;\
cp -r ui/ build/docker/linux/$$arch/ui;\
if [ $$arch == amd64 ]; then \
cp Dockerfile build/docker/linux/$$arch ;\
cp Dockerfile build/docker/linux/$$arch/Dockerfile.in ;\
else \
cp Dockerfile.build build/docker/linux/$$arch/Dockerfile ;\
cp Dockerfile.build build/docker/linux/$$arch/Dockerfile.in ;\
case $$arch in \
arm) \
BASEIMAGE=arm32v6 ;\
;; \
arm64) \
BASEIMAGE=arm64v8 ;\
;; \
*) \
BASEIMAGE=$$arch ;\
;; \
esac ;\
sed -e "s/alpine:latest/$$BASEIMAGE\\/alpine:latest/" -e "s/^\\s*RUN/#RUN/" build/docker/linux/$$arch/Dockerfile.in > build/docker/linux/$$arch/Dockerfile ;\
fi ;\
docker build -t $(NAME) build/docker/linux/$$arch ;\
docker tag $(NAME) $(DOCKER_IMAGE_NAME):$(NAME)-$$arch ;\
done
.PHONY: docker-push
docker-push:
@echo Pushing: $(VERSION) to $(DOCKER_IMAGE_NAME)
for arch in $(LINUX_ARCH); do \
docker push $(DOCKER_IMAGE_NAME):$(NAME)-$$arch ;\
done
manifest-tool push from-args --platforms $(PLATFORMS) --template $(DOCKER_IMAGE_NAME):podinfo-ARCH --target $(DOCKER_IMAGE_NAME):$(VERSION)
manifest-tool push from-args --platforms $(PLATFORMS) --template $(DOCKER_IMAGE_NAME):podinfo-ARCH --target $(DOCKER_IMAGE_NAME):latest
.PHONY: quay-push
quay-push:
@echo Pushing: $(VERSION) to quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
@docker build -t quay.io/$(DOCKER_IMAGE_NAME):$(VERSION) -f Dockerfile.ci . ; docker push quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
.PHONY: clean
clean:
rm -rf release
rm -rf build
.PHONY: gcr-build
gcr-build:
docker build -t gcr.io/$(DOCKER_IMAGE_NAME):$(VERSION) -f Dockerfile.ci .
.PHONY: test
test:
cd pkg/server ; go test -v -race ./...
GO111MODULE=on go test -v -race ./...
.PHONY: dep
dep:
go get -u github.com/golang/dep/cmd/dep
go get -u github.com/estesp/manifest-tool
build:
GO111MODULE=on GIT_COMMIT=$$(git rev-list -1 HEAD) && GO111MODULE=on CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$${GIT_COMMIT}" -a -o ./bin/podinfo ./cmd/podinfo/*
GO111MODULE=on GIT_COMMIT=$$(git rev-list -1 HEAD) && GO111MODULE=on CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$${GIT_COMMIT}" -a -o ./bin/podcli ./cmd/podcli/*
.PHONY: charts
charts:
cd charts/ && helm package podinfo/
cd charts/ && helm package podinfo-istio/
cd charts/ && helm package loadtest/
cd charts/ && helm package ambassador/
cd charts/ && helm package grafana/
cd charts/ && helm package ngrok/
mv charts/*.tgz docs/
helm repo index docs --url https://stefanprodan.github.io/k8s-podinfo --merge ./docs/index.yaml
build-charts:
helm lint charts/*
helm package charts/*
build-container:
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
push-container:
docker push $(DOCKER_IMAGE_NAME):$(VERSION)
docker tag $(DOCKER_IMAGE_NAME):$(VERSION) quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
docker push quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
version-set:
@next="$(TAG)" && \
current="$(VERSION)" && \
sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
echo "Version $$next set in code, deployment, chart and kustomize"
release:
git tag $(VERSION)
git push origin $(VERSION)

View File

@@ -1,17 +1,18 @@
# k8s-podinfo
# podinfo
[![Build Status](https://travis-ci.org/stefanprodan/podinfo.svg?branch=master)](https://travis-ci.org/stefanprodan/podinfo)
[![Docker Pulls](https://img.shields.io/docker/pulls/stefanprodan/podinfo)](https://hub.docker.com/r/stefanprodan/podinfo)
Podinfo is a tiny web application made with Go
that showcases best practices of running microservices in Kubernetes.
Specifications:
* Release automation (Make/TravisCI/CircleCI/Quay.io/Google Cloud Container Builder/Skaffold/Weave Flux)
* Multi-platform Docker image (amd64/arm/arm64/ppc64le/s390x)
* Health checks (readiness and liveness)
* Graceful shutdown on interrupt signals
* File watcher for secrets and configmaps
* Instrumented with Prometheus
* Tracing with Istio and Jeger
* Tracing with Istio and Jaeger
* Structured logging with zap
* 12-factor app with viper
* Fault injection (random errors and latency)
@@ -29,18 +30,44 @@ Web API:
* `GET /status/{code}` returns the status code
* `GET /panic` crashes the process with exit code 255
* `POST /echo` forwards the call to the backend service and echos the posted content
* `GET /env` returns the environment variables as a JSON array
* `GET /headers` returns a JSON with the request HTTP headers
* `GET /delay/{seconds}` waits for the specified period
* `POST /token` issues a JWT token valid for one minute `JWT=$(curl -sd 'anon' podinfo:9898/token | jq -r .token)`
* `GET /token/validate` validates the JWT token `curl -H "Authorization: Bearer $JWT" podinfo:9898/token/validate`
* `GET /configs` returns a JSON with configmaps and/or secrets mounted in the `config` volume
* `POST /write` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
* `GET /read/{hash}` returns the content of the file /data/hash if exists
* `POST /store` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
* `GET /store/{hash}` returns the content of the file /data/hash if exists
* `GET /ws/echo` echos content via websockets `podcli ws ws://localhost:9898/ws/echo`
* `GET /chunked/{seconds}` uses `transfer-encoding` type `chunked` to give a partial response and then waits for the specified period
### Guides
* [Deploy and upgrade with Helm](docs/1-deploy.md)
* [Horizontal Pod Auto-scaling](docs/2-autoscaling.md)
* [Monitoring and alerting with Prometheus](docs/3-monitoring.md)
* [StatefulSets with local persistent volumes](docs/4-statefulsets.md)
* [Expose Kubernetes services over HTTPS with Ngrok](docs/6-ngrok.md)
* [A/B Testing with Ambassador API Gateway](docs/5-canary.md)
* [Canary Deployments with Istio](docs/7-istio.md)
* [Automated canary deployments with Flagger and Istio](https://medium.com/google-cloud/automated-canary-deployments-with-flagger-and-istio-ac747827f9d1)
* [Kubernetes autoscaling with Istio metrics](https://medium.com/google-cloud/kubernetes-autoscaling-with-istio-metrics-76442253a45a)
* [Managing Helm releases the GitOps way](https://medium.com/google-cloud/managing-helm-releases-the-gitops-way-207a6ac6ff0e)
* [Expose Kubernetes services over HTTPS with Ngrok](https://stefanprodan.com/2018/expose-kubernetes-services-over-http-with-ngrok/)
### Install
Helm:
```bash
helm repo add sp https://stefanprodan.github.io/podinfo
helm upgrade --install --wait frontend \
--namespace test \
--set backend=http://backend-podinfo:9898/echo \
sp/podinfo
helm upgrade --install --wait backend \
--namespace test \
--set hpa.enabled=true \
sp/podinfo
```
Kustomize:
```bash
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
```

View File

@@ -1,21 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

View File

@@ -1,11 +0,0 @@
apiVersion: v1
appVersion: "0.29.0"
description: A Helm chart for Datawire Ambassador
name: ambassador
version: 0.1.0
sources:
- https://github.com/datawire/ambassador
maintainers:
- name: stefanprodan
email: stefanprodan@users.noreply.github.com
engine: gotpl

View File

@@ -1,63 +0,0 @@
# Ambassador
Ambassador is an open source, Kubernetes-native [microservices API gateway](https://www.getambassador.io/about/microservices-api-gateways) built on the [Envoy Proxy](https://www.envoyproxy.io/).
## TL;DR;
```console
$ helm install stable/ambassador
```
## Introduction
This chart bootstraps an [Ambassador](https://www.getambassador.io) deployment on
a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
## Prerequisites
- Kubernetes 1.7+
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install --name my-release stable/ambassador
```
The command deploys Ambassador API gateway on the Kubernetes cluster in the default configuration.
The [configuration](#configuration) section lists the parameters that can be configured during installation.
## Uninstalling the Chart
To uninstall/delete the `my-release` deployment:
```console
$ helm delete --purge my-release
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
The following tables lists the configurable parameters of the Ambassador chart and their default values.
| Parameter | Description | Default |
| ------------------------------- | ------------------------------------------ | ---------------------------------------------------------- |
| `image` | Image | `quay.io/datawire/ambassador`
| `imageTag` | Image tag | `0.29.0`
| `imagePullPolicy` | Image pull policy | `IfNotPresent`
| `replicaCount` | Number of Ambassador replicas | `1`
| `resources` | CPU/memory resource requests/limits | None
| `rbac.create` | If `true`, create and use RBAC resources | `true`
| `serviceAccount.create` | If `true`, create a new service account | `true`
| `serviceAccount.name` | Service account to be used | `ambassador`
| `service.type` | Service type to be used | `LoadBalancer`
| `adminService.create` | If `true`, create a service for Ambassador's admin UI | `true`
| `adminService.type` | Ambassador's admin service type to be used | `ClusterIP`
| `exporter.image` | Prometheus exporter image | `datawire/prom-statsd-exporter:0.6.0`
| `timing.restart` | The minimum number of seconds between Envoy restarts | `15`
| `timing.drain` | The number of seconds that the Envoy will wait for open connections to drain on a restart | `5`
| `timing.shutdown` | The number of seconds that Ambassador will wait for the old Envoy to clean up and exit on a restart | `10`

View File

@@ -1,15 +0,0 @@
1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "ambassador.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "ambassador.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ambassador.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "ambassador.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

View File

@@ -1,43 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "ambassador.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "ambassador.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "ambassador.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "ambassador.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "ambassador.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

View File

@@ -1,21 +0,0 @@
{{- if .Values.adminService.create -}}
apiVersion: v1
kind: Service
metadata:
name: {{ template "ambassador.fullname" . }}-admin
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.adminService.type }}
ports:
- port: 8877
targetPort: admin
protocol: TCP
name: admin
selector:
app: {{ template "ambassador.name" . }}
release: {{ .Release.Name }}
{{- end -}}

View File

@@ -1,78 +0,0 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "ambassador.fullname" . }}
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "ambassador.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "ambassador.name" . }}
release: {{ .Release.Name }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9102"
spec:
serviceAccountName: {{ template "ambassador.serviceAccountName" . }}
containers:
- name: statsd-sink
image: "{{ .Values.exporter.image }}"
ports:
- name: metrics
containerPort: 9102
- name: ambassador
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: admin
containerPort: 8877
env:
- name: AMBASSADOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: AMBASSADOR_RESTART_TIME
value: {{ .Values.timing.restart | quote }}
- name: AMBASSADOR_DRAIN_TIME
value: {{ .Values.timing.drain | quote }}
- name: AMBASSADOR_SHUTDOWN_TIME
value: {{ .Values.timing.shutdown | quote }}
livenessProbe:
httpGet:
path: /ambassador/v0/check_alive
port: admin
initialDelaySeconds: 30
periodSeconds: 3
readinessProbe:
httpGet:
path: /ambassador/v0/check_ready
port: admin
initialDelaySeconds: 30
periodSeconds: 3
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

View File

@@ -1,42 +0,0 @@
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: {{ template "ambassador.fullname" . }}
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
rules:
- apiGroups: [""]
resources:
- services
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["create", "update", "patch", "get", "list", "watch"]
- apiGroups: [""]
resources:
- secrets
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: {{ template "ambassador.fullname" . }}
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "ambassador.fullname" . }}
subjects:
- name: {{ template "ambassador.serviceAccountName" . }}
namespace: {{ .Release.Namespace | quote }}
kind: ServiceAccount
{{- end -}}

View File

@@ -1,23 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "ambassador.fullname" . }}
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
- port: 443
targetPort: https
protocol: TCP
name: https
selector:
app: {{ template "ambassador.name" . }}
release: {{ .Release.Name }}

View File

@@ -1,11 +0,0 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "ambassador.serviceAccountName" . }}
labels:
app: {{ template "ambassador.name" . }}
chart: {{ template "ambassador.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- end -}}

View File

@@ -1,56 +0,0 @@
# Default values for ambassador.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: quay.io/datawire/ambassador
tag: 0.29.0
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
adminService:
create: true
type: ClusterIP
rbac:
# Specifies whether RBAC resources should be created
create: true
serviceAccount:
# Specifies whether a service account should be created
create: true
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name:
resources: {}
# If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
exporter:
image: datawire/prom-statsd-exporter:0.6.0
timing:
# sets the minimum number of seconds between Envoy restarts
restart: 15
# sets the number of seconds that the Envoy will wait for open connections to drain on a restart
drain: 5
# sets the number of seconds that Ambassador will wait for the old Envoy to clean up and exit on a restart
shutdown: 10

View File

@@ -1,21 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

View File

@@ -1,5 +0,0 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: grafana
version: 0.1.0

View File

@@ -1,65 +0,0 @@
# Weave Cloud Grafana
Grafana v5 with Kubernetes dashboards and Prometheus and Weave Cloud data sources.
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install stable/grafana --name my-release \
--set service.type=NodePort \
--set token=WEAVE-TOKEN \
--set password=admin
```
The command deploys Grafana on the Kubernetes cluster in the default namespace.
The [configuration](#configuration) section lists the parameters that can be configured during installation.
## Uninstalling the Chart
To uninstall/delete the `my-release` deployment:
```console
$ helm delete --purge my-release
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
The following tables lists the configurable parameters of the Grafana chart and their default values.
Parameter | Description | Default
--- | --- | ---
`image.repository` | Image repository | `grafana/grafana`
`image.pullPolicy` | Image pull policy | `IfNotPresent`
`image.tag` | Image tag | `5.0.1`
`replicaCount` | desired number of pods | `1`
`resources` | pod resources | `none`
`tolerations` | List of node taints to tolerate | `[]`
`affinity` | node/pod affinities | `node`
`nodeSelector` | node labels for pod assignment | `{}`
`service.type` | type of service | `LoadBalancer`
`url` | Prometheus URL, used when Weave token is empty | `http://prometheus:9090`
`token` | Weave Cloud token | `none`
`user` | Grafana admin username | `admin`
`password` | Grafana admin password | `none`
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
```console
$ helm install stable/grafana --name my-release \
--set=token=WEAVE-TOKEN \
--set password=admin
```
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
```console
$ helm install stable/grafana --name my-release -f values.yaml
```
> **Tip**: You can use the default [values.yaml](values.yaml)
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,817 +0,0 @@
{
"annotations": {
"list": [
{
"$$hashKey": "object:246",
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 1,
"id": null,
"iteration": 1521457664773,
"links": [],
"panels": [
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "prometheus",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 0,
"y": 0
},
"id": 8,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "cores",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "sum(rate(container_cpu_usage_seconds_total{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[3m])) ",
"format": "time_series",
"intervalFactor": 2,
"refId": "A",
"step": 600
}
],
"thresholds": "",
"title": "CPU",
"type": "singlestat",
"valueFontSize": "110%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "prometheus",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 4,
"w": 8,
"x": 8,
"y": 0
},
"id": 9,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "GB",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "80%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "sum(container_memory_usage_bytes{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}) / 1024^3",
"format": "time_series",
"intervalFactor": 2,
"refId": "A",
"step": 600
}
],
"thresholds": "",
"title": "Memory",
"type": "singlestat",
"valueFontSize": "110%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "prometheus",
"editable": true,
"error": false,
"format": "Bps",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": false
},
"gridPos": {
"h": 4,
"w": 8,
"x": 16,
"y": 0
},
"id": 7,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": true
},
"tableColumn": "",
"targets": [
{
"expr": "sum(rate(container_network_transmit_bytes_total{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[3m])) + sum(rate(container_network_receive_bytes_total{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[3m])) ",
"format": "time_series",
"intervalFactor": 2,
"refId": "A",
"step": 600
}
],
"thresholds": "",
"title": "Network",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "prometheus",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 4
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"hideZero": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "max(kube_deployment_status_replicas{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "current replicas",
"refId": "A",
"step": 30
},
{
"expr": "min(kube_deployment_status_replicas_available{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "available",
"refId": "B",
"step": 30
},
{
"expr": "max(kube_deployment_status_replicas_unavailable{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "unavailable",
"refId": "C",
"step": 30
},
{
"expr": "min(kube_deployment_status_replicas_updated{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "updated",
"refId": "D",
"step": 30
},
{
"expr": "max(kube_deployment_spec_replicas{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "desired",
"refId": "E",
"step": 30
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Replicas",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"transparent": false,
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": false
}
]
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "prometheus",
"editable": true,
"error": false,
"format": "percent",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": true,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
"h": 6,
"w": 4,
"x": 20,
"y": 4
},
"id": 11,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"expr": "(min(kube_deployment_status_replicas_available{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod))\n/\n(min(kube_deployment_spec_replicas{deployment=\"$deployment_name\",namespace=\"$deployment_namespace\"}) without (instance, pod)) * 100\n",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "",
"refId": "A",
"step": 600
}
],
"thresholds": "50,80",
"title": "Availability",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "prometheus",
"fill": 1,
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 10
},
"id": 10,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sort": "current",
"sortDesc": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sort_desc(\n\nsum by (pod_name) (rate(container_cpu_usage_seconds_total{image!=\"\",container_name!=\"POD\",namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[1m])) \n\n)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "{{ pod_name }}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Pods CPU",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"label": "cores",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "prometheus",
"fill": 1,
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 16
},
"id": 13,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sort": "current",
"sortDesc": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sort_desc(\n\nsum by (pod_name) (container_memory_working_set_bytes{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}) \n\n)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "{{ pod_name }}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Pods Memory",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "bytes",
"label": "",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "prometheus",
"fill": 1,
"gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 22
},
"id": 12,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"sort": "current",
"sortDesc": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sort_desc(\n\nsum by (pod_name) (rate (container_network_receive_bytes_total{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[1m])) \n+\nsum by (pod_name) (rate (container_network_transmit_bytes_total{namespace=\"$deployment_namespace\",pod_name=~\"$deployment_name.*\"}[1m]))\n)",
"format": "time_series",
"intervalFactor": 2,
"legendFormat": "{{ pod_name }}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Pods Network I/O",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "Bps",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"refresh": "30s",
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"allValue": ".*",
"current": {
"text": "default",
"value": "default"
},
"datasource": "prometheus",
"hide": 0,
"includeAll": false,
"label": "Namespace",
"multi": false,
"name": "deployment_namespace",
"options": [],
"query": "label_values(kube_deployment_metadata_generation, namespace)",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": null,
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": null,
"current": {
"text": "ga-podinfo",
"value": "ga-podinfo"
},
"datasource": "prometheus",
"hide": 0,
"includeAll": false,
"label": "Deployment",
"multi": false,
"name": "deployment_name",
"options": [],
"query": "label_values(kube_deployment_metadata_generation{namespace=\"$deployment_namespace\"}, deployment)",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "deployment",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-5m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "browser",
"title": "Deployments",
"uid": "sgRyigkik",
"version": 2
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "grafana.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "grafana.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "grafana.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "grafana.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

View File

@@ -1,32 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "grafana.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "grafana.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "grafana.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,6 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "grafana.fullname" . }}-dashboards
data:
{{ (.Files.Glob "dashboards/*").AsConfig | indent 2 }}

View File

@@ -1,32 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "grafana.fullname" . }}-datasources
data:
datasources.yaml: |-
apiVersion: 1
deleteDatasources:
- name: prometheus
{{- if .Values.token }}
datasources:
- name: prometheus
type: prometheus
access: proxy
url: https://cloud.weave.works/api/prom
isDefault: true
editable: true
version: 1
basicAuth: true
basicAuthUser: weave
basicAuthPassword: {{ .Values.token }}
{{- else }}
datasources:
- name: prometheus
type: prometheus
access: proxy
url: {{ .Values.url }}
isDefault: true
editable: true
version: 1
{{- end }}

View File

@@ -1,81 +0,0 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "grafana.fullname" . }}
labels:
app: {{ template "grafana.fullname" . }}
chart: {{ template "grafana.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "grafana.fullname" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "grafana.fullname" . }}
release: {{ .Release.Name }}
annotations:
prometheus.io/scrape: 'false'
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 3000
protocol: TCP
# livenessProbe:
# httpGet:
# path: /
# port: http
# readinessProbe:
# httpGet:
# path: /
# port: http
env:
- name: GF_SECURITY_ADMIN_USER
value: {{ .Values.user }}
- name: GF_SECURITY_ADMIN_PASSWORD
value: {{ .Values.password }}
- name: GF_PATHS_PROVISIONING
value: /etc/grafana/provisioning/
volumeMounts:
- name: grafana
mountPath: /var/lib/grafana
- name: dashboards
mountPath: /etc/grafana/dashboards
- name: datasources
mountPath: /etc/grafana/provisioning/datasources
- name: providers
mountPath: /etc/grafana/provisioning/dashboards
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
volumes:
- name: grafana
emptyDir: {}
- name: dashboards
configMap:
name: {{ template "grafana.fullname" . }}-dashboards
- name: providers
configMap:
name: {{ template "grafana.fullname" . }}-providers
- name: datasources
configMap:
name: {{ template "grafana.fullname" . }}-datasources

View File

@@ -1,17 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "grafana.fullname" . }}-providers
data:
providers.yaml: |+
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: ''
type: file
disableDeletion: false
editable: true
options:
path: /etc/grafana/dashboards

View File

@@ -1,19 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "grafana.fullname" . }}
labels:
app: {{ template "grafana.name" . }}
chart: {{ template "grafana.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "grafana.fullname" . }}
release: {{ .Release.Name }}

View File

@@ -1,34 +0,0 @@
# Default values for grafana.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: grafana/grafana
tag: 5.0.1
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
user: admin
password:
url: http://prometheus:9090
token:

View File

@@ -1,21 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

View File

@@ -1,5 +0,0 @@
apiVersion: v1
appVersion: "1.0"
description: Hey load test Helm chart for Kubernetes
name: loadtest
version: 0.1.0

View File

@@ -1 +0,0 @@
{{ template "loadtest.fullname" . }} has been deployed successfully!

View File

@@ -1,32 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "loadtest.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "loadtest.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "loadtest.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,31 +0,0 @@
{{- $fullname := include "loadtest.fullname" . -}}
{{- $name := include "loadtest.name" . -}}
{{- $chart := include "loadtest.chart" . -}}
{{- $image := .Values.image -}}
{{- range $test := .Values.tests }}
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: {{ $fullname }}-{{ .name }}
labels:
app: {{ $name }}
chart: {{ $chart }}
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: loadtest
image: {{ $image }}
args:
- /bin/sh
- -c
- "hey -z 58s {{ $test.cmd }} {{ $test.url }}"
restartPolicy: OnFailure
{{- end -}}

View File

@@ -1,11 +0,0 @@
# Default values for loadtest.
image: stefanprodan/loadtest:latest
tests:
- name: "blue"
url: "https://canary.istio.weavedx.com/api/echo"
cmd: "-h2 -m POST -d '{test: 1}' -H 'X-API-Version: 0.6.0' -c 50 -q 5"
- name: "green"
url: "https://canary.istio.weavedx.com/api/echo"
cmd: "-h2 -m POST -d '{test: 2}' -H 'X-API-Version: 0.6.1' -c 10 -q 5"

View File

@@ -2,4 +2,4 @@ apiVersion: v1
appVersion: "1.0"
description: A Ngrok Helm chart for Kubernetes
name: ngrok
version: 0.1.0
version: 0.2.0

View File

@@ -41,6 +41,7 @@ Parameter | Description | Default
`service.type` | type of service | `ClusterIP`
`token` | Ngrok auth token | `none`
`expose.service` | Service address to be exposed as in `service-name:port` | `none`
`subdomain` | Ngrok subdomain | `none`
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

View File

@@ -28,6 +28,9 @@ spec:
command:
- ./ngrok
- http
{{- if .Values.subdomain }}
- --subdomain={{ .Values.subdomain }}
{{- end }}
- {{ .Values.expose.service }}
volumeMounts:
- name: config

View File

@@ -23,3 +23,5 @@ nodeSelector: {}
tolerations: []
affinity: {}
subdomain:

View File

@@ -1,21 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj

View File

@@ -1,12 +0,0 @@
apiVersion: v1
appVersion: "0.6.0"
description: Podinfo Helm chart for Istio
name: podinfo-istio
version: 0.1.0
home: https://github.com/stefanprodan/k8s-podinfo
sources:
- https://github.com/stefanprodan/k8s-podinfo
maintainers:
- name: stefanprodan
email: stefanprodan@users.noreply.github.com
engine: gotpl

View File

@@ -1,80 +0,0 @@
# Podinfo Istio
Podinfo is a tiny web application made with Go
that showcases best practices of running microservices in Kubernetes.
## Installing the Chart
Create an Istio enabled namespace:
```console
kubectl create namespace demo
kubectl label namespace demo istio-injection=enabled
```
Create an Istio Gateway in the `istio-system` namespace named `public-gateway`:
```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: public-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
tls:
httpsRedirect: true
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "*"
tls:
mode: SIMPLE
privateKey: /etc/istio/ingressgateway-certs/tls.key
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
```
Create the `frontend` release by specifying the external domain name:
```console
helm upgrade frontend --install ./charts/podinfo-istio \
--namespace=demo \
--set host=podinfo.example.com \
--set gateway.name=public-gateway \
--set gateway.create=false \
-f ./charts/podinfo-istio/frontend.yaml
```
Create the `backend` release:
```console
helm upgrade backend --install ./charts/podinfo-istio \
--namespace=demo \
-f ./charts/podinfo-istio/backend.yaml
```
Create the `store` release:
```console
helm upgrade store --install ./charts/podinfo-istio \
--namespace=demo \
-f ./charts/podinfo-istio/store.yaml
```
Start load test:
```console
helm upgrade --install loadtest ./charts/loadtest \
--namespace=loadtesting
```

View File

@@ -1,34 +0,0 @@
#!/usr/bin/env bash
#Usage: fswatch -o ./podinfo-istio/ | xargs -n1 ./podinfo-istio/apply.sh
set -e
MARK='\033[0;32m'
NC='\033[0m'
log (){
echo -e "$(date +%Y-%m-%dT%H:%M:%S%z) ${MARK}${1}${NC}"
}
log "installing frontend"
helm upgrade frontend --install ./podinfo-istio \
--namespace=demo \
--set host=canary.istio.weavedx.com \
--set gateway.name=public-gateway \
--set gateway.create=false \
-f ./podinfo-istio/frontend.yaml
log "installing backend"
helm upgrade backend --install ./podinfo-istio \
--namespace=demo \
-f ./podinfo-istio/backend.yaml
log "installing store"
helm upgrade store --install ./podinfo-istio \
--namespace=demo \
-f ./podinfo-istio/store.yaml
log "finished installing frontend, backend and store"

View File

@@ -1,21 +0,0 @@
# Default values for backend demo.
# expose the blue/green deployments inside the cluster
host: backend
# stable release
blue:
replicas: 2
tag: "1.0.0"
backend: http://store:9898/api/echo
# canary release
green:
replicas: 2
tag: "1.0.0"
routing:
# target green callers
- match:
- sourceLabels:
color: green
backend: http://store:9898/api/echo

View File

@@ -1,39 +0,0 @@
# Default values for frontend demo.
# external domain
host:
exposeHost: true
# no more than one Gateway can be created on a cluster
# if TLS is enabled the istio-ingressgateway-certs secret must exist in istio-system ns
# if you have a Gateway running you can set the name to your own gateway and turn off create
gateway:
name: public-gateway
create: false
tls: true
httpsRedirect: true
# stable release
blue:
replicas: 2
tag: "1.0.0"
message: "Greetings human! Gabi is THE BEST!!!!"
backend: http://backend:9898/api/echo
# canary release
green:
replicas: 2
tag: "1.0.0"
routing:
# target Safari
- match:
- headers:
user-agent:
regex: "^(?!.*Chrome).*Safari.*"
# target API clients by version
- match:
- headers:
x-api-version:
regex: "^(v{0,1})0\\.6\\.([1-9]).*"
message: "Greetings from the green frontend"
backend: http://backend:9898/api/echo

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
# Default values for backend demo.
# expose the store deployment inside the cluster
host: store
# load balance 80/20 between blue and green
blue:
replicas: 2
tag: "1.0.0"
backend: https://httpbin.org/anything
weight: 80
green:
replicas: 2
tag: "1.0.0"
backend: https://httpbin.org/anything
externalServices:
- httpbin.org

View File

@@ -1 +0,0 @@
{{ template "podinfo-istio.fullname" . }} has been deployed successfully!

View File

@@ -1,36 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "podinfo-istio.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
The release name is used as a full name.
*/}}
{{- define "podinfo-istio.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- define "podinfo-istio.blue" -}}
{{- printf "%s-%s" .Release.Name "blue" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "podinfo-istio.green" -}}
{{- printf "%s-%s" .Release.Name "green" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "podinfo-istio.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,78 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "podinfo-istio.blue" . }}
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
color: blue
version: {{ .Values.blue.tag }}
spec:
replicas: {{ .Values.blue.replicas }}
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: {{ template "podinfo-istio.fullname" . }}
color: blue
template:
metadata:
labels:
app: {{ template "podinfo-istio.fullname" . }}
color: blue
version: {{ .Values.blue.tag }}
annotations:
prometheus.io/scrape: 'true'
spec:
terminationGracePeriodSeconds: 30
containers:
- name: podinfod
image: "{{ .Values.blue.repository }}:{{ .Values.blue.tag }}"
imagePullPolicy: {{ .Values.imagePullPolicy }}
command:
- ./podinfo
- --port={{ .Values.containerPort }}
- --level={{ .Values.logLevel }}
- --random-delay={{ .Values.blue.faults.delay }}
- --random-error={{ .Values.blue.faults.error }}
env:
- name: PODINFO_UI_COLOR
value: blue
{{- if .Values.blue.backend }}
- name: PODINFO_BACKEND_URL
value: {{ .Values.blue.backend }}
{{- end }}
{{- if .Values.blue.message }}
- name: PODINFO_UI_MESSAGE
value: {{ .Values.blue.message }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.containerPort }}
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
volumeMounts:
- name: data
mountPath: /data
resources:
{{ toYaml .Values.resources | indent 12 }}
volumes:
- name: data
emptyDir: {}

View File

@@ -1,20 +0,0 @@
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: {{ template "podinfo-istio.fullname" . }}
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
host: {{ template "podinfo-istio.fullname" . }}
subsets:
- name: blue
labels:
color: blue
{{- if gt .Values.green.replicas 0.0 }}
- name: green
labels:
color: green
{{- end }}

View File

@@ -1,22 +0,0 @@
{{- if .Values.externalServices -}}
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: {{ template "podinfo-istio.fullname" . }}-external-svcs
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
hosts:
{{- range .Values.externalServices }}
- {{ . }}
{{- end }}
location: MESH_EXTERNAL
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
{{- end }}

View File

@@ -1,31 +0,0 @@
{{- if .Values.gateway.create -}}
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: {{ .Values.gateway.name }}
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
tls:
httpsRedirect: {{ .Values.gateway.httpsRedirect }}
{{- if .Values.gateway.tls }}
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "*"
tls:
mode: SIMPLE
privateKey: /etc/istio/ingressgateway-certs/tls.key
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
{{- end }}
{{- end }}

View File

@@ -1,80 +0,0 @@
{{- if gt .Values.green.replicas 0.0 -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "podinfo-istio.green" . }}
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
color: green
version: {{ .Values.green.tag }}
spec:
replicas: {{ .Values.green.replicas }}
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: {{ template "podinfo-istio.fullname" . }}
color: green
template:
metadata:
labels:
app: {{ template "podinfo-istio.fullname" . }}
color: green
version: {{ .Values.green.tag }}
annotations:
prometheus.io/scrape: 'true'
spec:
terminationGracePeriodSeconds: 30
containers:
- name: podinfod
image: "{{ .Values.green.repository }}:{{ .Values.green.tag }}"
imagePullPolicy: {{ .Values.imagePullPolicy }}
command:
- ./podinfo
- --port={{ .Values.containerPort }}
- --level={{ .Values.logLevel }}
- --random-delay={{ .Values.green.faults.delay }}
- --random-error={{ .Values.green.faults.error }}
env:
- name: PODINFO_UI_COLOR
value: green
{{- if .Values.green.backend }}
- name: PODINFO_BACKEND_URL
value: {{ .Values.green.backend }}
{{- end }}
{{- if .Values.green.message }}
- name: PODINFO_UI_MESSAGE
value: {{ .Values.green.message }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.containerPort }}
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
volumeMounts:
- name: data
mountPath: /data
resources:
{{ toYaml .Values.resources | indent 12 }}
volumes:
- name: data
emptyDir: {}
{{- end }}

View File

@@ -1,18 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "podinfo-istio.fullname" . }}
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: ClusterIP
ports:
- port: {{ .Values.containerPort }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "podinfo-istio.fullname" . }}

View File

@@ -1,43 +0,0 @@
{{- $host := .Release.Name -}}
{{- $timeout := .Values.timeout -}}
{{- $greenWeight := (sub 100 (.Values.blue.weight|int)) | int -}}
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: {{ template "podinfo-istio.fullname" . }}
labels:
app: {{ template "podinfo-istio.fullname" . }}
chart: {{ template "podinfo-istio.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
hosts:
- {{ .Values.host }}
{{- if .Values.exposeHost }}
gateways:
- {{ .Values.gateway.name }}.istio-system.svc.cluster.local
{{- end }}
http:
{{- if gt .Values.green.replicas 0.0 }}
{{- range .Values.green.routing }}
- match:
{{ toYaml .match | indent 6 }}
route:
- destination:
host: {{ $host }}
subset: green
timeout: {{ $timeout }}
{{- end }}
{{- end }}
- route:
- destination:
host: {{ template "podinfo-istio.fullname" . }}
subset: blue
weight: {{ .Values.blue.weight }}
{{- if gt .Values.green.replicas 0.0 }}
- destination:
host: {{ template "podinfo-istio.fullname" . }}
subset: green
weight: {{ $greenWeight }}
{{- end }}
timeout: {{ $timeout }}

View File

@@ -1,60 +0,0 @@
# Default values for podinfo-istio.
# host can be an extarnal domain or a local one
host: podinfo
# if the host is an external domain must be exposed via the Gateway
exposeHost: false
timeout: 30s
# creates public-gateway.istio-system.svc.cluster.local
# no more than one Gateway can be created on a cluster
# if TLS is enabled the istio-ingressgateway-certs secret must exist in istio-system ns
# if you have a Gateway running you can set the name to your own gateway and turn off create
gateway:
name: public-gateway
create: false
tls: false
httpsRedirect: false
# authorise external https services
#externalServices:
# - api.github.com
# - apis.google.com
# - googleapis.com
# stable release
# by default all traffic goes to blue
blue:
replicas: 2
repository: quay.io/stefanprodan/podinfo
tag: "1.0.0"
# green must have at at least one replica to set weight under 100
weight: 100
message:
backend:
faults:
delay: false
error: false
# canary release
# disabled with 0 replicas
green:
replicas: 0
repository: quay.io/stefanprodan/podinfo
tag: "1.0.0"
message:
backend:
routing:
faults:
delay: false
error: false
# blue/green common settings
logLevel: info
containerPort: 9898
imagePullPolicy: IfNotPresent
resources:
limits:
requests:
cpu: 1m
memory: 16Mi

View File

@@ -1,12 +1,12 @@
apiVersion: v1
appVersion: "1.0.0"
description: Podinfo Helm chart for Kubernetes
version: 2.0.0
appVersion: 2.0.0
name: podinfo
version: 1.0.0
home: https://github.com/stefanprodan/k8s-podinfo
sources:
- https://github.com/stefanprodan/k8s-podinfo
maintainers:
- name: stefanprodan
email: stefanprodan@users.noreply.github.com
engine: gotpl
description: Podinfo Helm chart for Kubernetes
home: https://github.com/stefanprodan/podinfo
maintainers:
- email: stefanprodan@users.noreply.github.com
name: stefanprodan
sources:
- https://github.com/stefanprodan/podinfo

View File

@@ -1,4 +1,4 @@
apiVersion: apps/v1beta2
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "podinfo.fullname" . }}
@@ -7,8 +7,6 @@ metadata:
chart: {{ template "podinfo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
color: {{ .Values.color }}
version: {{ .Values.image.tag }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
@@ -18,15 +16,11 @@ spec:
selector:
matchLabels:
app: {{ template "podinfo.name" . }}
color: {{ .Values.color }}
version: {{ .Values.image.tag }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "podinfo.name" . }}
color: {{ .Values.color }}
version: {{ .Values.image.tag }}
release: {{ .Release.Name }}
annotations:
prometheus.io/scrape: 'true'
@@ -57,20 +51,24 @@ spec:
- name: http
containerPort: {{ .Values.service.containerPort }}
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
exec:
command:
- podcli
- check
- http
- localhost:{{ .Values.service.containerPort }}/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:{{ .Values.service.containerPort }}/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
volumeMounts:
- name: data
mountPath: /data

View File

@@ -11,8 +11,8 @@ metadata:
"helm.sh/hook": test-success
spec:
containers:
- name: curl
image: radial/busyboxplus:curl
- name: tools
image: giantswarm/tiny-tools
command: ["/bin/sh", "/scripts/ping.sh"]
env:
- name: PODINFO_SVC
@@ -38,4 +38,4 @@ metadata:
data:
ping.sh: |
#!/bin/sh
curl -sSd "$(curl -sSd 'test' ${PODINFO_SVC}/write)" ${PODINFO_SVC}/read|grep test
curl -sS ${PODINFO_SVC}/store/$(curl -sSd 'test' ${PODINFO_SVC}/store | jq -r .hash) |grep test

View File

@@ -1,6 +1,6 @@
# Default values for podinfo.
replicaCount: 2
replicaCount: 1
logLevel: info
color: blue
backend: #http://backend-podinfo:9898/echo
@@ -12,7 +12,7 @@ faults:
image:
repository: quay.io/stefanprodan/podinfo
tag: 1.0.0
tag: 2.0.0
pullPolicy: IfNotPresent
service:

View File

@@ -1,4 +1,4 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build','-f' , 'Dockerfile.ci', '-t', 'gcr.io/$PROJECT_ID/podinfo:$BRANCH_NAME-$SHORT_SHA', '.']
args: ['build','-f' , 'Dockerfile', '-t', 'gcr.io/$PROJECT_ID/podinfo:$BRANCH_NAME-$SHORT_SHA', '.']
images: ['gcr.io/$PROJECT_ID/podinfo:$BRANCH_NAME-$SHORT_SHA']

245
cmd/podcli/check.go Normal file
View File

@@ -0,0 +1,245 @@
package main
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/spf13/cobra"
"go.uber.org/zap"
)
var (
retryCount int
retryDelay time.Duration
method string
body string
timeout time.Duration
)
var checkCmd = &cobra.Command{
Use: `check`,
Short: "Health check commands",
Long: "Commands for running health checks",
}
var checkUrlCmd = &cobra.Command{
Use: `http [address]`,
Short: "HTTP(S) health check",
Example: ` check http https://httpbin.org/anything --method=POST --retry=2 --delay=2s --timeout=3s --body='{"test"=1}'`,
RunE: runCheck,
}
var checkTcpCmd = &cobra.Command{
Use: `tcp [address]`,
Short: "TCP health check",
Example: ` check tcp httpbin.org:443 --retry=1 --delay=2s --timeout=2s`,
RunE: runCheckTCP,
}
var checkCertCmd = &cobra.Command{
Use: `cert [address]`,
Short: "SSL/TLS certificate validity check",
Example: ` check cert httpbin.org`,
RunE: runCheckCert,
}
func init() {
checkUrlCmd.Flags().StringVar(&method, "method", "GET", "HTTP method")
checkUrlCmd.Flags().StringVar(&body, "body", "", "HTTP POST/PUT content")
checkUrlCmd.Flags().IntVar(&retryCount, "retry", 0, "times to retry the HTTP call")
checkUrlCmd.Flags().DurationVar(&retryDelay, "delay", 1*time.Second, "wait duration between retries")
checkUrlCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
checkCmd.AddCommand(checkUrlCmd)
checkTcpCmd.Flags().IntVar(&retryCount, "retry", 0, "times to retry the TCP check")
checkTcpCmd.Flags().DurationVar(&retryDelay, "delay", 1*time.Second, "wait duration between retries")
checkTcpCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
checkCmd.AddCommand(checkTcpCmd)
checkCmd.AddCommand(checkCertCmd)
rootCmd.AddCommand(checkCmd)
}
func runCheck(cmd *cobra.Command, args []string) error {
if retryCount < 0 {
return fmt.Errorf("--retry is required")
}
if len(args) < 1 {
return fmt.Errorf("address is required! example: check http https://httpbin.org")
}
address := args[0]
if !strings.HasPrefix(address, "http://") && !strings.HasPrefix(address, "https://") {
address = fmt.Sprintf("http://%s", address)
}
for n := 0; n <= retryCount; n++ {
if n != 1 {
time.Sleep(retryDelay)
}
req, err := http.NewRequest(method, address, bytes.NewBuffer([]byte(body)))
if err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
os.Exit(1)
}
ctx, cancel := context.WithTimeout(req.Context(), timeout)
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
cancel()
if err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
continue
}
if resp.Body != nil {
resp.Body.Close()
}
if resp.StatusCode >= 200 && resp.StatusCode < 400 {
logger.Info("check succeed",
zap.String("address", address),
zap.Int("status code", resp.StatusCode),
zap.String("response size", fmtContentLength(resp.ContentLength)))
os.Exit(0)
} else {
logger.Info("check failed",
zap.String("address", address),
zap.Int("status code", resp.StatusCode))
continue
}
}
os.Exit(1)
return nil
}
func runCheckTCP(cmd *cobra.Command, args []string) error {
if retryCount < 0 {
return fmt.Errorf("--retry is required")
}
if len(args) < 1 {
return fmt.Errorf("address is required! example: check tcp httpbin.org:80")
}
address := args[0]
for n := 0; n <= retryCount; n++ {
if n != 1 {
time.Sleep(retryDelay)
}
conn, err := net.DialTimeout("tcp", address, timeout)
if err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
continue
}
conn.Close()
logger.Info("check succeed", zap.String("address", address))
os.Exit(0)
}
os.Exit(1)
return nil
}
func runCheckCert(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("address is required! example: check cert httpbin.org")
}
host := args[0]
if !strings.HasPrefix(host, "https://") {
host = "https://" + host
}
u, err := url.Parse(host)
if err != nil {
logger.Info("check failed",
zap.String("address", host),
zap.Error(err))
os.Exit(1)
}
address := u.Hostname() + ":443"
ipConn, err := net.DialTimeout("tcp", address, 5*time.Second)
if err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
os.Exit(1)
}
defer ipConn.Close()
conn := tls.Client(ipConn, &tls.Config{
InsecureSkipVerify: true,
ServerName: u.Hostname(),
})
if err = conn.Handshake(); err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
os.Exit(1)
}
defer conn.Close()
addr := conn.RemoteAddr()
_, _, err = net.SplitHostPort(addr.String())
if err != nil {
logger.Info("check failed",
zap.String("address", address),
zap.Error(err))
os.Exit(1)
}
cert := conn.ConnectionState().PeerCertificates[0]
timeNow := time.Now()
if timeNow.After(cert.NotAfter) {
logger.Info("check failed",
zap.String("address", address),
zap.String("issuer", cert.Issuer.CommonName),
zap.String("subject", cert.Subject.CommonName),
zap.Time("expired", cert.NotAfter))
os.Exit(1)
}
logger.Info("check succeed",
zap.String("address", address),
zap.String("issuer", cert.Issuer.CommonName),
zap.String("subject", cert.Subject.CommonName),
zap.Time("notAfter", cert.NotAfter),
zap.Time("notBefore", cert.NotBefore))
return nil
}
func fmtContentLength(b int64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}

365
cmd/podcli/code.go Normal file
View File

@@ -0,0 +1,365 @@
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/hashicorp/go-getter"
"github.com/spf13/cobra"
)
var (
codeProjectName string
codeGitUser string
codeVersion string
codeProjectPath string
)
var codeCmd = &cobra.Command{
Use: `code`,
Short: "Code commands",
}
var codeInitCmd = &cobra.Command{
Use: `init [name]`,
Short: "initialize podinfo code repo",
Example: ` code init demo-app --version=v1.2.0 --git-user=stefanprodan`,
RunE: runCodeInit,
}
func init() {
codeInitCmd.Flags().StringVar(&codeGitUser, "git-user", "", "GitHub user or org")
codeInitCmd.Flags().StringVar(&codeVersion, "version", "master", "podinfo repo tag or branch name")
codeInitCmd.Flags().StringVar(&codeProjectPath, "path", ".", "destination repo")
codeCmd.AddCommand(codeInitCmd)
rootCmd.AddCommand(codeCmd)
}
func runCodeInit(cmd *cobra.Command, args []string) error {
if len(codeGitUser) < 0 {
return fmt.Errorf("--git-user is required")
}
if len(args) < 1 {
return fmt.Errorf("project name is required")
}
codeProjectName = args[0]
pwd, err := os.Getwd()
if err != nil {
log.Fatalf("Error getting pwd: %s", err)
os.Exit(1)
}
tmpPath := "/tmp/k8s-podinfo"
versionName := fmt.Sprintf("k8s-podinfo-%s", codeVersion)
downloadURL := fmt.Sprintf("https://github.com/stefanprodan/podinfo/archive/%s.zip", codeVersion)
client := &getter.Client{
Src: downloadURL,
Dst: tmpPath,
Pwd: pwd,
Mode: getter.ClientModeAny,
}
fmt.Printf("Downloading %s\n", downloadURL)
if err := client.Get(); err != nil {
log.Fatalf("Error downloading: %s", err)
os.Exit(1)
}
pkgFrom := "github.com/stefanprodan/podinfo"
pkgTo := fmt.Sprintf("github.com/%s/%s", codeGitUser, codeProjectName)
if err := replaceImports(tmpPath, pkgFrom, pkgTo); err != nil {
log.Fatalf("Error parsing imports: %s", err)
os.Exit(1)
}
dirs := []string{"pkg", "cmd", "ui", "vendor", ".github"}
for _, dir := range dirs {
err = os.MkdirAll(path.Join(codeProjectPath, dir), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
if err := copyDir(path.Join(tmpPath, versionName, dir), path.Join(codeProjectPath, dir)); err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
files := []string{"Gopkg.toml", "Gopkg.lock"}
for _, file := range files {
if err := copyFile(path.Join(tmpPath, versionName, file), path.Join(codeProjectPath, file)); err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
newContent := strings.Replace(string(fileContent), pkgFrom, pkgTo, -1)
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
projFrom := "stefanprodan/podinfo"
projTo := fmt.Sprintf("%s/%s", codeGitUser, codeProjectName)
makeFiles := []string{"Makefile.gh", "Dockerfile.gh"}
for _, file := range makeFiles {
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
destFile := strings.Replace(file, ".gh", "", -1)
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
err = ioutil.WriteFile(path.Join(codeProjectPath, destFile), []byte(newContent), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
workflows := []string{".github/main.workflow"}
for _, file := range workflows {
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
newContent := strings.Replace(string(fileContent), "Dockerfile.gh", "Dockerfile", -1)
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
dockerFiles := []string{"Dockerfile.ci"}
for _, file := range dockerFiles {
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
travisFiles := []string{"travis.lite.yml"}
for _, file := range travisFiles {
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
destFile := strings.Replace(file, "travis.lite.yml", ".travis.yml", -1)
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
err = ioutil.WriteFile(path.Join(codeProjectPath, destFile), []byte(newContent), os.ModePerm)
if err != nil {
log.Fatalf("Error: %s", err)
os.Exit(1)
}
}
err = gitPush()
if err != nil {
log.Fatalf("git push error: %s", err)
os.Exit(1)
}
fmt.Println("Initialization finished")
return nil
}
func gitPush() error {
cmdPush := fmt.Sprintf("git add . && git commit -m \"sync %s\" && git push", codeVersion)
cmd := exec.Command("sh", "-c", cmdPush)
output, err := cmd.Output()
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
func replaceImports(projectPath string, pkgFrom string, pkgTo string) error {
regexImport, err := regexp.Compile(`(?s)(import(.*?)\)|import.*$)`)
if err != nil {
return err
}
regexImportedPackage, err := regexp.Compile(`"(.*?)"`)
if err != nil {
return err
}
found := []string{}
err = filepath.Walk(projectPath, func(path string, info os.FileInfo, err error) error {
if filepath.Ext(path) == ".go" {
bts, err := ioutil.ReadFile(path)
if err != nil {
return err
}
content := string(bts)
matches := regexImport.FindAllString(content, -1)
isExists := false
isReplaceable:
for _, each := range matches {
for _, eachLine := range strings.Split(each, "\n") {
matchesInline := regexImportedPackage.FindAllString(eachLine, -1)
if err != nil {
return err
}
for _, eachSubline := range matchesInline {
if strings.Contains(eachSubline, pkgFrom) {
isExists = true
break isReplaceable
}
}
}
}
if isExists {
content = strings.Replace(content, `"`+pkgFrom+`"`, `"`+pkgTo+`"`, -1)
content = strings.Replace(content, `"`+pkgFrom+`/`, `"`+pkgTo+`/`, -1)
found = append(found, path)
}
err = ioutil.WriteFile(path, []byte(content), info.Mode())
if err != nil {
return err
}
}
return nil
})
if err != nil {
fmt.Println("ERROR", err.Error())
}
if len(found) == 0 {
fmt.Println("Nothing replaced")
} else {
fmt.Printf("Go imports total %d file replaced\n", len(found))
}
return nil
}
func copyDir(src string, dst string) error {
si, err := os.Stat(src)
if err != nil {
return err
}
if !si.IsDir() {
return fmt.Errorf("source is not a directory")
}
err = os.MkdirAll(dst, si.Mode())
if err != nil {
return err
}
entries, err := ioutil.ReadDir(src)
if err != nil {
return err
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
err = copyDir(srcPath, dstPath)
if err != nil {
return err
}
} else {
// Skip symlinks.
if entry.Mode()&os.ModeSymlink != 0 {
continue
}
err = copyFile(srcPath, dstPath)
if err != nil {
return err
}
}
}
return nil
}
func copyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
if e := out.Close(); e != nil {
err = e
}
}()
_, err = io.Copy(out, in)
if err != nil {
return
}
err = out.Sync()
if err != nil {
return
}
si, err := os.Stat(src)
if err != nil {
return
}
err = os.Chmod(dst, si.Mode())
if err != nil {
return
}
return
}

38
cmd/podcli/main.go Normal file
View File

@@ -0,0 +1,38 @@
package main
import (
"fmt"
"github.com/spf13/cobra"
"go.uber.org/zap"
"log"
"os"
"strings"
)
var rootCmd = &cobra.Command{
Use: "podcli",
Short: "podinfo command line",
Long: `
podinfo command line utilities`,
}
var (
logger *zap.Logger
)
func main() {
var err error
logger, err = zap.NewDevelopment()
if err != nil {
log.Fatalf("can't initialize zap logger: %v", err)
}
defer logger.Sync()
rootCmd.SetArgs(os.Args[1:])
if err := rootCmd.Execute(); err != nil {
e := err.Error()
fmt.Println(strings.ToUpper(e[:1]) + e[1:])
os.Exit(1)
}
}

20
cmd/podcli/version.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import (
"fmt"
"github.com/spf13/cobra"
"github.com/stefanprodan/podinfo/pkg/version"
)
func init() {
rootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: `version`,
Short: "Prints podcli version",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println(version.VERSION)
return nil
},
}

143
cmd/podcli/ws.go Normal file
View File

@@ -0,0 +1,143 @@
package main
import (
"encoding/hex"
"fmt"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"github.com/chzyer/readline"
"github.com/fatih/color"
"github.com/gorilla/websocket"
"github.com/spf13/cobra"
"go.uber.org/zap"
)
var origin string
func init() {
wsCmd.Flags().StringVarP(&origin, "origin", "o", "", "websocket origin")
rootCmd.AddCommand(wsCmd)
}
var wsCmd = &cobra.Command{
Use: `ws [address]`,
Short: "Websocket client",
Example: ` ws localhost:9898/ws/echo`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("address is required")
}
address := args[0]
if !strings.HasPrefix(address, "ws://") && !strings.HasPrefix(address, "wss://") {
address = fmt.Sprintf("ws://%s", address)
}
dest, err := url.Parse(address)
if err != nil {
return err
}
if origin != "" {
} else {
originURL := *dest
if dest.Scheme == "wss" {
originURL.Scheme = "https"
} else {
originURL.Scheme = "http"
}
origin = originURL.String()
}
err = connect(dest.String(), origin, &readline.Config{
Prompt: "> ",
})
if err != nil {
logger.Info("websocket closed", zap.Error(err))
}
return nil
},
}
type session struct {
ws *websocket.Conn
rl *readline.Instance
errChan chan error
}
func connect(url, origin string, rlConf *readline.Config) error {
headers := make(http.Header)
headers.Add("Origin", origin)
ws, _, err := websocket.DefaultDialer.Dial(url, headers)
if err != nil {
return err
}
rl, err := readline.NewEx(rlConf)
if err != nil {
return err
}
defer rl.Close()
sess := &session{
ws: ws,
rl: rl,
errChan: make(chan error),
}
go sess.readConsole()
go sess.readWebsocket()
return <-sess.errChan
}
func (s *session) readConsole() {
for {
line, err := s.rl.Readline()
if err != nil {
s.errChan <- err
return
}
err = s.ws.WriteMessage(websocket.TextMessage, []byte(line))
if err != nil {
s.errChan <- err
return
}
}
}
func bytesToFormattedHex(bytes []byte) string {
text := hex.EncodeToString(bytes)
return regexp.MustCompile("(..)").ReplaceAllString(text, "$1 ")
}
func (s *session) readWebsocket() {
rxSprintf := color.New(color.FgGreen).SprintfFunc()
for {
msgType, buf, err := s.ws.ReadMessage()
if err != nil {
fmt.Fprint(s.rl.Stdout(), rxSprintf("< %s\n", err.Error()))
os.Exit(1)
return
}
var text string
switch msgType {
case websocket.TextMessage:
text = string(buf)
case websocket.BinaryMessage:
text = bytesToFormattedHex(buf)
default:
s.errChan <- fmt.Errorf("unknown websocket frame type: %d", msgType)
return
}
fmt.Fprint(s.rl.Stdout(), rxSprintf("< %s\n", text))
}
}

View File

@@ -2,25 +2,26 @@ package main
import (
"fmt"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/stefanprodan/podinfo/pkg/api"
"github.com/stefanprodan/podinfo/pkg/signals"
"github.com/stefanprodan/podinfo/pkg/version"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/stefanprodan/k8s-podinfo/pkg/api"
"github.com/stefanprodan/k8s-podinfo/pkg/signals"
"github.com/stefanprodan/k8s-podinfo/pkg/version"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func main() {
// flags definition
fs := pflag.NewFlagSet("default", pflag.ContinueOnError)
fs.Int("port", 9898, "port")
fs.Int("port-metrics", 0, "metrics port")
fs.String("level", "info", "log level debug, info, warn, error, flat or panic")
fs.String("backend-url", "", "backend service URL")
fs.Duration("http-client-timeout", 2*time.Minute, "client timeout duration")
@@ -36,7 +37,8 @@ func main() {
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.Int("stress-memory", 0, "MB of data to load into memory")
versionFlag := fs.Bool("version", false, "get version number")
versionFlag := fs.BoolP("version", "v", false, "get version number")
// parse flags
err := fs.Parse(os.Args[1:])
@@ -56,6 +58,7 @@ func main() {
viper.BindPFlags(fs)
viper.RegisterAlias("backendUrl", "backend-url")
hostname, _ := os.Hostname()
viper.SetDefault("jwt-secret", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
viper.Set("hostname", hostname)
viper.Set("version", version.VERSION)
viper.Set("revision", version.REVISION)
@@ -81,6 +84,12 @@ func main() {
// start stress tests if any
beginStressTest(viper.GetInt("stress-cpu"), viper.GetInt("stress-memory"), logger)
// validate port
if _, err := strconv.Atoi(viper.GetString("port")); err != nil {
port, _ := fs.GetInt("port")
viper.Set("port", strconv.Itoa(port))
}
// load HTTP server config
var srvCfg api.Config
if err := viper.Unmarshal(&srvCfg); err != nil {
@@ -91,7 +100,7 @@ func main() {
logger.Info("Starting podinfo",
zap.String("version", viper.GetString("version")),
zap.String("revision", viper.GetString("revision")),
zap.String("port", viper.GetString("port")),
zap.String("port", srvCfg.Port),
)
// start HTTP server

View File

@@ -1,52 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: blue
labels:
app: blue
spec:
replicas: 2
selector:
matchLabels:
app: blue
template:
metadata:
labels:
app: blue
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:0.0.9
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -logtostderr=true
- -v=2
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 3
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"
limits:
memory: "256Mi"
cpu: "100m"

View File

@@ -1,22 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: blue
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: blue
prefix: /
host: podinfo.test
service: blue.default:9898
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: blue

View File

@@ -1,52 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: green
labels:
app: green
spec:
replicas: 2
selector:
matchLabels:
app: green
template:
metadata:
labels:
app: green
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:0.0.9
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -logtostderr=true
- -v=2
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 3
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"
limits:
memory: "256Mi"
cpu: "100m"

View File

@@ -1,51 +0,0 @@
# test cmd:
# while true; do sleep 1; curl -sS -H "Host: podinfo.test" -H "x-subscription: trial" http://35.198.122.99:30080|grep HOSTNAME;done
---
apiVersion: v1
kind: Service
metadata:
name: green
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: green
prefix: /
host: podinfo.test
service: green.default:9898
weight: 50
headers:
X-Subscription: trial
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: green
---
apiVersion: v1
kind: Service
metadata:
name: blue-trial
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: blue-trial
prefix: /
host: podinfo.test
service: blue.default:9898
headers:
X-Subscription: trial
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: blue

View File

@@ -1,70 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ambassador
labels:
component: ambassador
spec:
replicas: 2
selector:
matchLabels:
component: ambassador
template:
metadata:
labels:
component: ambassador
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9102"
spec:
serviceAccountName: ambassador
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
component: ambassador
topologyKey: kubernetes.io/hostname
containers:
- name: ambassador
image: quay.io/datawire/ambassador:0.26.1
ports:
- containerPort: 80
name: http
- containerPort: 443
name: https
- containerPort: 8877
name: admin
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 200m
memory: 100Mi
env:
- name: AMBASSADOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
livenessProbe:
httpGet:
path: /ambassador/v0/check_alive
port: 8877
initialDelaySeconds: 10
periodSeconds: 3
readinessProbe:
httpGet:
path: /ambassador/v0/check_ready
port: 8877
initialDelaySeconds: 10
periodSeconds: 3
- name: statsd-sink
image: datawire/prom-statsd-exporter:0.6.0
ports:
- containerPort: 9102
name: metrics
restartPolicy: Always

View File

@@ -1,36 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: ambassador
rules:
- apiGroups: [""]
resources:
- services
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["create", "update", "patch", "get", "list", "watch"]
- apiGroups: [""]
resources:
- secrets
verbs: ["get", "list", "watch"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ambassador
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: ambassador
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ambassador
subjects:
- kind: ServiceAccount
name: ambassador
namespace: default

View File

@@ -1,24 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
labels:
component: ambassador
name: ambassador
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
- name: https
port: 443
targetPort: 443
nodePort: 30443
- name: admin
port: 8877
targetPort: 8877
nodePort: 30877
selector:
component: ambassador

View File

@@ -1,83 +0,0 @@
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: podinfo
spec:
replicas: 1
template:
metadata:
labels:
app: podinfo
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:0.0.9
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -logtostderr=true
- -v=2
volumeMounts:
- name: metadata
mountPath: /etc/podinfod/metadata
readOnly: true
- name: resources
mountPath: /etc/podinfod/resources
readOnly: true
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 3
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"
limits:
memory: "256Mi"
cpu: "100m"
volumes:
- name: metadata
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
- name: resources
downwardAPI:
items:
- path: "cpu_limit"
resourceFieldRef:
containerName: podinfod
resource: limits.cpu
- path: "cpu_request"
resourceFieldRef:
containerName: podinfod
resource: requests.cpu
- path: "mem_limit"
resourceFieldRef:
containerName: podinfod
resource: limits.memory
- path: "mem_request"
resourceFieldRef:
containerName: podinfod
resource: requests.memory

View File

@@ -1,15 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: podinfo-clusterip
labels:
app: podinfo
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: podinfo

View File

@@ -1,16 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: podinfo-nodeport
labels:
app: podinfo
spec:
type: NodePort
ports:
- port: 9898
targetPort: 9898
nodePort: 31190
protocol: TCP
selector:
app: podinfo

View File

@@ -1,48 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: canarya-podinfo
labels:
app: canarya-podinfo
spec:
replicas: 2
selector:
matchLabels:
app: canarya-podinfo
template:
metadata:
labels:
app: canarya-podinfo
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: quay.io/stefanprodan/podinfo:0.2.0
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -debug=true
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"

View File

@@ -1,27 +0,0 @@
# test cmd:
# while true; do sleep 1; curl -sS -H "Host: podinfo.test" -H "x-user: insider" http://35.198.122.99:30080/version;done
---
apiVersion: v1
kind: Service
metadata:
name: canarya-podinfo
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: canarya-podinfo
prefix: /
host: podinfo.test
service: canarya-podinfo.default:9898
headers:
X-User: insider
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: canarya-podinfo

View File

@@ -1,48 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: canaryb-podinfo
labels:
app: canaryb-podinfo
spec:
replicas: 2
selector:
matchLabels:
app: canaryb-podinfo
template:
metadata:
labels:
app: canaryb-podinfo
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: quay.io/stefanprodan/podinfo:0.2.1
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -debug=true
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"

View File

@@ -1,28 +0,0 @@
# test cmd:
# while true; do sleep 1; curl -sS -H "Host: podinfo.test" -H "x-user: insider" http://35.198.122.99:30080/version;done
---
apiVersion: v1
kind: Service
metadata:
name: canaryb-podinfo
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: canaryb-podinfo
prefix: /
host: podinfo.test
service: canaryb-podinfo.default:9898
weight: 10
headers:
X-User: insider
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: canaryb-podinfo

View File

@@ -1,49 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ga-podinfo
labels:
app: ga-podinfo
spec:
replicas: 2
selector:
matchLabels:
app: ga-podinfo
template:
metadata:
labels:
app: ga-podinfo
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: quay.io/stefanprodan/podinfo:0.1.0
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -logtostderr=true
- -v=2
ports:
- containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"

View File

@@ -1,22 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: ga-podinfo
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: ga-podinfo
prefix: /
host: podinfo.test
service: ga-podinfo.default:9898
spec:
type: ClusterIP
ports:
- port: 9898
targetPort: 9898
protocol: TCP
selector:
app: ga-podinfo

View File

@@ -1,28 +0,0 @@
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: public-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
tls:
httpsRedirect: true
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "*"
tls:
mode: SIMPLE
privateKey: /etc/istio/ingressgateway-certs/tls.key
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt

View File

@@ -1,17 +0,0 @@
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: grafana
namespace: istio-system
spec:
hosts:
- "grafana.istio.weavedx.com"
gateways:
- public-gateway.istio-system.svc.cluster.local
http:
- route:
- destination:
host: grafana
timeout: 30s

View File

@@ -1,17 +0,0 @@
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: grafanax
namespace: istio-system
spec:
hosts:
- "grafanax.istio.weavedx.com"
gateways:
- public-gateway.istio-system.svc.cluster.local
http:
- route:
- destination:
host: grafanax
timeout: 30s

View File

@@ -1,17 +0,0 @@
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: jaeger
namespace: istio-system
spec:
hosts:
- "jaeger.istio.weavedx.com"
gateways:
- public-gateway.istio-system.svc.cluster.local
http:
- route:
- destination:
host: jaeger-query
timeout: 30s

View File

@@ -1,53 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: podinfo-canary
namespace: test
labels:
app: podinfo
release: canary
spec:
replicas: 1
selector:
matchLabels:
app: podinfo
release: canary
template:
metadata:
labels:
app: podinfo
release: canary
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: quay.io/stefanprodan/podinfo:0.2.2
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -debug=true
ports:
- name: http
containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"

View File

@@ -1,18 +0,0 @@
---
apiVersion: v1
kind: Service
metadata:
name: podinfo-canary
namespace: test
labels:
app: podinfo-canary
spec:
type: ClusterIP
ports:
- name: http
port: 9898
targetPort: http
protocol: TCP
selector:
app: podinfo
release: canary

View File

@@ -1,53 +0,0 @@
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: podinfo-ga
namespace: test
labels:
app: podinfo
release: ga
spec:
replicas: 1
selector:
matchLabels:
app: podinfo
release: ga
template:
metadata:
labels:
app: podinfo
release: ga
annotations:
prometheus.io/scrape: 'true'
spec:
containers:
- name: podinfod
image: quay.io/stefanprodan/podinfo:0.2.1
imagePullPolicy: Always
command:
- ./podinfo
- -port=9898
- -debug=true
ports:
- name: http
containerPort: 9898
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 9898
initialDelaySeconds: 1
periodSeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /healthz
port: 9898
initialDelaySeconds: 1
periodSeconds: 10
failureThreshold: 2
resources:
requests:
memory: "32Mi"
cpu: "10m"

Some files were not shown because too many files have changed in this diff Show More