Compare commits

..

85 Commits
3.2.1 ... 4.0.5

Author SHA1 Message Date
Stefan Prodan
f43f9b2eb6 Merge pull request #87 from stefanprodan/release-4.0.5
Release v4.0.5
2020-06-15 10:34:21 +03:00
stefanprodan
9a46ed3182 Release v4.0.5 2020-06-15 09:56:10 +03:00
Stefan Prodan
82b7007c5d Merge pull request #86 from stefanprodan/redis-chart
Add Redis deployment to Helm chart
2020-06-15 09:54:44 +03:00
stefanprodan
806f0dbe82 Add Redis deployment to Helm chart 2020-06-14 15:35:34 +03:00
Stefan Prodan
936018e5bb Merge pull request #85 from stefanprodan/alpine-3.12
Update Alpine to 3.12
2020-06-12 16:55:54 +03:00
stefanprodan
1b4131b5ad Update Alpine to 3.12 2020-06-12 13:49:06 +03:00
Stefan Prodan
b98a9dcc1a Merge pull request #84 from stefanprodan/release-4.0.4
Release v4.0.4
2020-06-12 13:46:58 +03:00
stefanprodan
8860e57362 Release v4.0.4 2020-06-12 13:40:07 +03:00
Stefan Prodan
f1ecea6b53 Merge pull request #83 from stefanprodan/pod-annotations
Add pod annotations to chart options
2020-06-12 13:33:31 +03:00
stefanprodan
ebc6493990 Add pod annotations to chart options 2020-06-12 13:00:54 +03:00
Stefan Prodan
a2f9216fe4 Merge pull request #82 from stefanprodan/release-4.0.3
Release v4.0.3
2020-06-06 13:31:28 +03:00
stefanprodan
27436ed538 Release v4.0.3 2020-06-06 09:55:21 +03:00
Stefan Prodan
c103a50423 Merge pull request #81 from alaa/master
Enable gRPC reflection protocol
2020-06-06 09:01:24 +03:00
Alaa Qutaish
5ac16f0f98 Enable gRPC reflection protocol 2020-06-05 17:16:29 +02:00
Stefan Prodan
b4138fdb4d Merge pull request #80 from stefanprodan/release-4.0.2
Release v4.0.2
2020-05-29 13:50:31 +03:00
stefanprodan
a2e6fd0ef1 Release v4.0.2 2020-05-29 13:24:11 +03:00
Stefan Prodan
c2aaf7a962 Merge pull request #79 from stefanprodan/cve-scan
Add CVE scanning with trivy
2020-05-29 12:46:07 +03:00
stefanprodan
a066ff5385 Add CVE scanning with trivy 2020-05-29 12:39:55 +03:00
Stefan Prodan
113360052b Merge pull request #78 from stefanprodan/release-4.0.1
Release 4.0.1
2020-05-28 10:46:58 +03:00
stefanprodan
a24e3e539c Release 4.0.1 2020-05-28 10:41:56 +03:00
Stefan Prodan
ed8a14d4d9 Merge pull request #77 from stefanprodan/e2e-helm
Consolidate e2e and unit tests
2020-05-28 10:36:37 +03:00
stefanprodan
d2798e1a24 Consolidate tests 2020-05-28 10:21:50 +03:00
stefanprodan
369014455c Use helm-gh-pages action 2020-05-28 10:13:45 +03:00
Stefan Prodan
db1b8a7acd Merge pull request #76 from seaneagan/helm2_tests
Add end-to-end tests for Helm v2 and v3
2020-05-28 10:11:45 +03:00
Sean Eagan
cc9231ae10 Test for helm 2 support 2020-05-27 15:59:38 -05:00
Sean Eagan
03ba47a0be helm tests: Helm 2 support
The `test-success` hook is supported by Helm 2 and 3.
2020-05-27 11:34:56 -05:00
Stefan Prodan
ab953493ee Merge pull request #74 from stefanprodan/release-4.0.0
Release 4.0.0
2020-05-27 18:28:14 +03:00
stefanprodan
c04ee365e6 Release 4.0.0 2020-05-27 18:14:55 +03:00
Stefan Prodan
26e8935520 Merge pull request #73 from stefanprodan/gh-actions-e2e
Migrate CI to GitHub Actions
2020-05-27 18:13:19 +03:00
stefanprodan
dd027359e6 Add goreleaser to release workflow 2020-05-27 17:56:18 +03:00
stefanprodan
cf26a9cefc Remove CircleCI e2e tests 2020-05-27 17:30:57 +03:00
stefanprodan
026b40876c Add linting workflow 2020-05-27 17:18:54 +03:00
stefanprodan
fd1814052a Add opencontainers metadata 2020-05-27 17:02:23 +03:00
stefanprodan
98c2853ec3 Publish Helm chart on release 2020-05-27 16:45:07 +03:00
stefanprodan
b2ca15b8af Add Helm publish action 2020-05-27 16:26:08 +03:00
stefanprodan
55e7178dad Refactor Helm action 2020-05-27 13:06:54 +03:00
stefanprodan
ea55d3facf Run end-to-end tests with Github Actions 2020-05-22 11:49:04 +03:00
stefanprodan
a72aa7a184 Remove ngrok chart 2020-05-22 10:45:22 +03:00
Stefan Prodan
b4248cae1e Merge pull request #72 from stefanprodan/multi-arch-build
Push releases to Docker Hub for AMD64, ARM64 and ARM v6/v7
2020-05-21 12:59:40 +03:00
stefanprodan
7d2bc4905a Push releases to Docker Hub for ARM64 and ARM v6/v7 2020-05-20 17:35:38 +03:00
stefanprodan
f75f6e9fbc Publish multi-arch image with Docker buildx 2020-05-20 15:56:11 +03:00
Stefan Prodan
713d1094a2 Merge pull request #71 from stefanprodan/register-instance
Register hostname and version in cache
2020-05-20 13:57:19 +03:00
stefanprodan
3197ad3e45 Register hostname and version in cache
If the caching server is online, podinfo registers its hostname and version in Redis. The set expires after one minute and it's refreshed every 30 seconds.
2020-05-20 13:51:07 +03:00
Stefan Prodan
92f415d633 Merge pull request #70 from stefanprodan/redis-cache-api
Add cache CRUD API
2020-05-20 13:15:03 +03:00
stefanprodan
0352a3c822 Add Helm test for the cache routes 2020-05-20 13:05:50 +03:00
stefanprodan
5ba5808722 Add cache CRUD API 2020-05-20 12:59:27 +03:00
Stefan Prodan
1d416a8513 Merge pull request #69 from seaneagan/helm2and3tests
Reverts tests as Jobs
2020-05-20 12:04:19 +03:00
Sean Eagan
95028a0fb0 Reverts tests as Jobs
This reverts the #61 change to use test Jobs, which was premature
since this feature hasn't been back ported to Helm 2 yet, which
leads to the tests not being run there.

It would be possible to use presence of .Capabilities.TillerVersion
to implement tests differently for Helm 2 vs 3, but this seems
not worth the trouble.
2020-05-19 15:27:08 -05:00
Stefan Prodan
b45cc75329 Merge pull request #67 from stefanprodan/release-3.3.1
Release v3.3.1
2020-05-16 11:46:00 +03:00
stefanprodan
79bbf76ece Release v3.3.1 2020-05-16 11:01:21 +03:00
Stefan Prodan
a8c7300174 Merge pull request #66 from stefanprodan/linkerd-profile-update
Add cache routes to Linkerd profile
2020-05-16 10:58:26 +03:00
stefanprodan
a60f28ac2f Update Kubernetes Kind to v0.8.1 2020-05-16 10:16:49 +03:00
stefanprodan
adba061f77 Update ingress API version 2020-05-16 10:15:36 +03:00
stefanprodan
8f15e4e00a Fix Helm tests 2020-05-16 10:14:45 +03:00
stefanprodan
07db5a6583 Add cache routes to Linkerd profile 2020-05-16 10:14:22 +03:00
Stefan Prodan
3e6d61e77e Merge pull request #65 from stefanprodan/release-3.3.0
Release v3.3.0
2020-05-16 10:07:12 +03:00
stefanprodan
c7c7d699c9 Release v3.3.0 2020-05-16 10:00:51 +03:00
Stefan Prodan
067751c67d Merge pull request #64 from stefanprodan/cache-api
Add cache API
2020-05-16 09:59:19 +03:00
stefanprodan
73b658d711 Add cache API
- implement cache with Redis
- add cache-server to args and config
- add Redis deployment to webapp overlays
2020-05-16 09:53:17 +03:00
Stefan Prodan
e5516b38cb Merge pull request #63 from stefanprodan/release-3.2.4
Release v3.2.4
2020-05-15 13:17:35 +03:00
stefanprodan
39130004d5 Release v3.2.4 2020-05-15 13:02:08 +03:00
Stefan Prodan
d4b615e3a2 Merge pull request #62 from stefanprodan/base-image
Push base image to Docker Hub
2020-05-15 13:00:18 +03:00
stefanprodan
98e133a7be Push base image to Docker Hub 2020-05-15 12:49:22 +03:00
Stefan Prodan
7674b76dab Merge pull request #60 from seaneagan/helm_test_fault
Support simulating helm test failure and timeout
2020-05-14 23:57:16 +03:00
Stefan Prodan
8fa39d90be Merge pull request #61 from seaneagan/helm3_tests_should_be_jobs
Helm 3 tests should be Jobs
2020-05-14 22:35:33 +03:00
Sean Eagan
638bdc8e83 Helm 3 tests should be Jobs
Without this "helm.sh/hook-delete-policy": before-hook-creation" does not work.
2020-05-14 09:12:53 -05:00
Sean Eagan
b565a67dec Support simulating helm test failure and timeout
This is to support testing of https://github.com/fluxcd/helm-operator/issues/369.
2020-05-13 14:22:24 -05:00
stefanprodan
65d077291b Add reconciler RBAC to webapp manifests 2020-05-01 20:29:55 +03:00
Stefan Prodan
e9d11c247e Merge pull request #58 from ytsarev/quote-message
Quote ui message in deployment template
2020-04-30 23:23:27 +03:00
Yury Tsarev
126ac55801 Quote ui message in deployment template
* To handle rare situation of digit-only message like 270 and
avoid associated failure during helm install
```
ReadString: expects " or n, but found 2, error found in #10 byte of ...|,"value":270},
{"name|..., bigger context ...|se"],"env":[{"name":"PODINFO_UI_MESSAGE","value":270},
```
2020-04-30 21:47:49 +02:00
Stefan Prodan
306aac3e65 Merge pull request #57 from stefanprodan/release-3.2.3
Release v3.2.3
2020-04-29 00:23:16 +03:00
stefanprodan
55318b0c20 Release v3.2.3 2020-04-28 19:20:23 +03:00
Stefan Prodan
1865faf7ce Merge pull request #56 from stefanprodan/webapp-demo
Add webapp demo
2020-04-28 19:18:28 +03:00
stefanprodan
9edd7abbe8 Include webapp demo in release 2020-04-28 19:13:01 +03:00
stefanprodan
1c4acc0b33 Add webapp demo kustomizations 2020-04-28 19:12:44 +03:00
stefanprodan
6274f16b9b Add webapp demo manifests 2020-04-28 19:12:25 +03:00
stefanprodan
93e338a964 Add app common label to kustomization 2020-04-15 12:22:49 +03:00
Stefan Prodan
73b03b77fc Merge pull request #54 from hiddeco/chart/readme-fix
chart: align README with actual values file
2020-04-04 13:36:58 +03:00
Hidde Beydals
0135757fbd chart: remove redundant codeblock opening 2020-04-04 12:32:54 +02:00
Hidde Beydals
ea1fe87d49 chart: align README with actual values file 2020-04-04 12:31:01 +02:00
Stefan Prodan
363a6a8fe6 Merge pull request #53 from stefanprodan/prep-3.2.2
Release v3.2.2
2020-04-02 17:16:13 +03:00
stefanprodan
8491738c8a Release v3.2.2 2020-04-02 17:10:40 +03:00
Stefan Prodan
361179fad9 Merge pull request #52 from stefanprodan/prometheus-operator
chart: add Prometheus Operator service monitor
2020-04-02 17:05:58 +03:00
stefanprodan
13eb7c42cd chart: add Prometheus Operator service monitor 2020-04-02 16:58:46 +03:00
stefanprodan
e4ecd98b83 chart: change label selectors to full name 2020-04-02 16:48:07 +03:00
91 changed files with 1677 additions and 628 deletions

View File

@@ -1,112 +0,0 @@
version: 2.1
jobs:
e2e-kubernetes:
machine: true
steps:
- checkout
- run:
name: Build podinfo container
command: e2e/build.sh
- run:
name: Start Kubernetes Kind cluster
command: e2e/bootstrap.sh
- run:
name: Install podinfo with Helm v3
command: e2e/install.sh
- run:
name: Run Helm tests
command: e2e/test.sh
push-container:
docker:
- image: circleci/golang:1.14
working_directory: ~/build
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run: make build-container
- run: |
if [ -z "$CIRCLE_TAG" ]; then
echo "Not a release, skipping container push";
else
echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin;
echo $QUAY_PASS | docker login -u $QUAY_USER --password-stdin quay.io;
make push-container;
fi
push-binary:
docker:
- image: circleci/golang:1.14
steps:
- checkout
- run: curl -sL https://git.io/goreleaser | bash
push-helm-charts:
docker:
- image: circleci/golang:1.14
steps:
- checkout
- run:
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: 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: |
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 "Not a release! Skip charts publish"
fi
workflows:
version: 2
build-test:
jobs:
- e2e-kubernetes
release:
jobs:
- push-binary:
filters:
branches:
ignore: /.*/
tags:
ignore: /^chart.*/
- push-container:
filters:
branches:
ignore: /.*/
tags:
ignore: /^chart.*/
- push-helm-charts:
requires:
- push-container
filters:
branches:
ignore: /.*/
tags:
ignore: /^chart.*/

6
.github/actions/helm/Dockerfile vendored Normal file
View File

@@ -0,0 +1,6 @@
FROM stefanprodan/alpine-base:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

15
.github/actions/helm/action.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: 'helm'
description: 'A GitHub Action to run helm commands'
author: 'Stefan Prodan'
branding:
icon: 'command'
color: 'blue'
inputs:
helm-version:
description: Helm version to use
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.helm-version }}

24
.github/actions/helm/entrypoint.sh vendored Normal file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
HELM_VERSION=$1
BIN_DIR="$GITHUB_WORKSPACE/bin"
main() {
mkdir -p ${BIN_DIR}
tmpDir=$(mktemp -d)
pushd $tmpDir >& /dev/null
curl -sSL https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar xz
cp linux-amd64/helm ${BIN_DIR}/helm
popd >& /dev/null
rm -rf $tmpDir
}
main
echo "::add-path::$BIN_DIR"
echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin"

View File

@@ -0,0 +1,6 @@
FROM stefanprodan/alpine-base:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,9 @@
name: 'github-release-notes'
description: 'A GitHub Action to run github-release-notes commands'
author: 'Stefan Prodan'
branding:
icon: 'command'
color: 'blue'
runs:
using: 'docker'
image: 'Dockerfile'

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
VERSION=0.2.0
BIN_DIR="$GITHUB_WORKSPACE/bin"
main() {
mkdir -p ${BIN_DIR}
tmpDir=$(mktemp -d)
pushd $tmpDir >& /dev/null
curl -sSL https://github.com/buchanae/github-release-notes/releases/download/${VERSION}/github-release-notes-linux-amd64-${VERSION}.tar.gz | tar xz
cp github-release-notes ${BIN_DIR}/github-release-notes
popd >& /dev/null
rm -rf $tmpDir
}
main
echo "::add-path::$BIN_DIR"
echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin"

23
.github/workflows/cve-scan.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: cve-scan
on:
push:
branches:
- 'master'
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build image
id: build
run: |
IMAGE=test/podinfo:${GITHUB_SHA}
docker build -t ${IMAGE} .
echo "::set-output name=image::$IMAGE"
- name: Scan image
uses: docker://docker.io/aquasec/trivy:latest
with:
args: --cache-dir /var/lib/trivy --no-progress --exit-code 1 --severity MEDIUM,HIGH,CRITICAL ${{ steps.build.outputs.image }}

50
.github/workflows/e2e.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: e2e
on:
pull_request:
push:
branches:
- 'master'
jobs:
kind-helm:
strategy:
matrix:
helm-version:
- 2.16.6
- 3.2.1
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.4.0
- name: Build container image
run: |
GIT_COMMIT=$(git rev-list -1 HEAD) && \
docker build -t test/podinfo:latest --build-arg "REVISION=${GIT_COMMIT}" .
kind load docker-image test/podinfo:latest
- name: Setup Helm
uses: ./.github/actions/helm
with:
helm-version: ${{ matrix.helm-version }}
- name: Install Tiller
if: ${{ startsWith(matrix.helm-version, '2') }}
run: |
kubectl --namespace kube-system create sa tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
helm init --service-account tiller --upgrade --wait
- name: Deploy
run: |
helm upgrade -i podinfo ./charts/podinfo \
--set image.repository=test/podinfo \
--set image.tag=latest \
--namespace=default
- name: Run integration tests
run: |
kubectl rollout status deployment/podinfo --timeout=1m
helm test podinfo
- name: Debug failure
if: failure()
run: |
kubectl logs -l app=podinfo || true

46
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
name: release
on:
push:
tags: '*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: crazy-max/ghaction-docker-buildx@v1
- name: Publish multi-arch image
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker buildx build --platform "linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64" \
--output "type=image,push=true" \
--build-arg "REVISION=${GITHUB_SHA}" \
--build-arg "VERSION=${GITHUB_REF#refs/tags/}" \
--build-arg "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
--tag "docker.io/stefanprodan/podinfo:${GITHUB_REF#refs/tags/}" \
--tag "docker.io/stefanprodan/podinfo:latest" \
--file Dockerfile .
- name: Publish base image
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: stefanprodan/podinfo-base
tags: latest
- name: Publish helm chart
uses: stefanprodan/helm-gh-pages@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ./.github/actions/release-notes
- name: Generate release notes
run: |
echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org stefanprodan -repo podinfo -since-latest-release >> /tmp/release.txt
- name: Publish release
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --release-notes=/tmp/release.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,17 +1,43 @@
on: [push, pull_request]
name: test
on:
pull_request:
push:
branches:
- 'master'
jobs:
validate:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: kubeval
- name: Checkout
uses: actions/checkout@v2
- name: Restore Go cache
uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
- name: Run unit tests
run: make test
- name: Check if working tree is dirty
run: |
if [[ $(git diff --stat) != '' ]]; then
echo 'run make test and commit changes'
exit 1
fi
- name: Validate Helm chart
uses: stefanprodan/kube-tools@v1
with:
command: |
helmv3 template ./charts/podinfo | kubeval --strict
- name: Validate kustomization
uses: stefanprodan/kube-tools@v1
with:
command: |
kustomize build ./kustomize | kubeval --strict
- name: conftest
uses: stefanprodan/kube-tools@v1
with:
command: |
kustomize build ./kustomize | conftest test -p .github/policy -

View File

@@ -1,4 +1,6 @@
FROM golang:1.14 as builder
FROM golang:1.14-alpine as builder
ARG REVISION
RUN mkdir -p /podinfo/
@@ -8,24 +10,35 @@ COPY . .
RUN 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}" \
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-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}" \
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
-a -o bin/podcli cmd/podcli/*
FROM alpine:3.11
FROM alpine:3.12
ARG BUILD_DATE
ARG VERSION
ARG REVISION
LABEL maintainer="stefanprodan" \
org.opencontainers.image.created=$BUILD_DATE \
org.opencontainers.image.url="https://github.com/stefanprodan/podinfo" \
org.opencontainers.image.source="https://github.com/stefanprodan/podinfo" \
org.opencontainers.image.version=$VERSION \
org.opencontainers.image.revision=$REVISION \
org.opencontainers.image.vendor="stefanprodan" \
org.opencontainers.image.title="podinfo" \
org.opencontainers.image.description="Go microservice template for Kubernetes" \
org.opencontainers.image.licenses="MIT"
RUN addgroup -S app \
&& adduser -S -g app app \
&& apk --no-cache add \
curl openssl netcat-openbsd
ca-certificates curl netcat-openbsd
WORKDIR /home/app

10
Dockerfile.base Normal file
View File

@@ -0,0 +1,10 @@
FROM golang:1.14
WORKDIR /workspace
# copy modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache modules
RUN go mod download

View File

@@ -33,6 +33,12 @@ build-charts:
build-container:
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
build-base:
docker build -f Dockerfile.base -t $(DOCKER_REPOSITORY)/podinfo-base:latest .
push-base: build-base
docker push $(DOCKER_REPOSITORY)/podinfo-base:latest
test-container:
@docker rm -f podinfo || true
@docker run -dp 9898:9898 --name=podinfo $(DOCKER_IMAGE_NAME):$(VERSION)
@@ -57,6 +63,10 @@ version-set:
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 && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
echo "Version $$next set in code, deployment, chart and kustomize"
release:

View File

@@ -1,7 +1,8 @@
# podinfo
[![CircleCI](https://circleci.com/gh/stefanprodan/podinfo.svg?style=svg)](https://circleci.com/gh/stefanprodan/podinfo)
[![conftest](https://github.com/stefanprodan/podinfo/workflows/test/badge.svg)](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/test.yml)
[![e2e](https://github.com/stefanprodan/podinfo/workflows/e2e/badge.svg)](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/e2e.yml)
[![test](https://github.com/stefanprodan/podinfo/workflows/test/badge.svg)](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/test.yml)
[![cve-scan](https://github.com/stefanprodan/podinfo/workflows/cve-scan/badge.svg)](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/cve-scan.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/stefanprodan/podinfo)](https://goreportcard.com/report/github.com/stefanprodan/podinfo)
[![Docker Pulls](https://img.shields.io/docker/pulls/stefanprodan/podinfo)](https://hub.docker.com/r/stefanprodan/podinfo)
@@ -22,6 +23,8 @@ Specifications:
* Helm and Kustomize installers
* End-to-End testing with Kubernetes Kind and Helm
* Kustomize testing with GitHub Actions and Open Policy Agent
* Multi-arch container image with Docker buildx and Github Actions
* CVE scanning with trivy
Web API:
@@ -41,6 +44,9 @@ Web API:
* `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/PUT /cache/{key}` saves the posted content to Redis
* `GET /cache/{key}` returns the content from Redis if the key exists
* `DELETE /cache/{key}` deletes the key from Redis 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`

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 Ngrok Helm chart for Kubernetes
name: ngrok
version: 0.2.0

View File

@@ -1,64 +0,0 @@
# Ngrok
Expose Kubernetes service with [Ngrok](https://ngrok.com).
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install sp/ngrok --name my-release \
--set token=NGROK-TOKEN \
--set expose.service=podinfo:9898
```
The command deploys Ngrok 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 | `stefanprodan/ngrok`
`image.pullPolicy` | Image pull policy | `IfNotPresent`
`image.tag` | Image tag | `latest`
`replicaCount` | desired number of pods | `1`
`tolerations` | List of node taints to tolerate | `[]`
`affinity` | node/pod affinities | `node`
`nodeSelector` | node labels for pod assignment | `{}`
`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,
```console
$ helm upgrade --install --wait tunel \
--set token=NGROK-TOKEN \
--set service.type=NodePort \
--set expose.service=podinfo:9898 \
sp/ngrok
```
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
```console
$ helm install sp/grafana --name my-release -f values.yaml
```
> **Tip**: You can use the default [values.yaml](values.yaml)
```

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 "ngrok.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 "ngrok.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ngrok.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 "ngrok.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 "ngrok.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 "ngrok.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 "ngrok.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,12 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "ngrok.fullname" . }}
data:
ngrok.yml: |-
web_addr: 0.0.0.0:4040
update: false
log: stdout
{{- if .Values.token }}
authtoken: {{ .Values.token }}
{{- end }}

View File

@@ -1,65 +0,0 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "ngrok.fullname" . }}
labels:
app: {{ template "ngrok.name" . }}
chart: {{ template "ngrok.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "ngrok.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "ngrok.name" . }}
release: {{ .Release.Name }}
annotations:
prometheus.io/scrape: 'false'
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command:
- ./ngrok
- http
{{- if .Values.subdomain }}
- --subdomain={{ .Values.subdomain }}
{{- end }}
- {{ .Values.expose.service }}
volumeMounts:
- name: config
mountPath: /home/ngrok/.ngrok2
ports:
- name: http
containerPort: 4040
protocol: TCP
livenessProbe:
httpGet:
path: /api/tunnels
port: http
initialDelaySeconds: 10
periodSeconds: 30
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: config
configMap:
name: {{ template "ngrok.fullname" . }}

View File

@@ -1,19 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "ngrok.fullname" . }}
labels:
app: {{ template "ngrok.name" . }}
chart: {{ template "ngrok.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 "ngrok.name" . }}
release: {{ .Release.Name }}

View File

@@ -1,27 +0,0 @@
# Default values for ngrok.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: stefanprodan/ngrok
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 4040
expose:
service: ga-podinfo:9898
token: 4i3rDinhLqMHtvez71N9S_38rkS7onwv77VFNZTaUR6
nodeSelector: {}
tolerations: []
affinity: {}
subdomain:

View File

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

View File

@@ -8,8 +8,9 @@ that showcases best practices of running microservices in Kubernetes.
To install the chart with the release name `my-release`:
```console
$ helm repo add sp https://stefanprodan.github.io/podinfo
$ helm upgrade my-release --install sp/podinfo
$ helm repo add podinfo https://stefanprodan.github.io/podinfo
$ helm upgrade -i my-release podinfo/podinfo
```
The command deploys podinfo on the Kubernetes cluster in the default namespace.
@@ -20,7 +21,7 @@ The [configuration](#configuration) section lists the parameters that can be con
To uninstall/delete the `my-release` deployment:
```console
$ helm delete --purge my-release
$ helm delete my-release
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
@@ -29,60 +30,77 @@ The command removes all the Kubernetes components associated with the chart and
The following tables lists the configurable parameters of the podinfo chart and their default values.
Parameter | Description | Default
Parameter | Default | Description
--- | --- | ---
`affinity` | node/pod affinities | None
`backend` | echo backend URL | None
`backends` | echo backend URL array | None
`faults.delay` | random HTTP response delays between 0 and 5 seconds | `false`
`faults.error` | 1/3 chances of a random HTTP response error | `false`
`faults.unhealthy` | when set, the healthy state is never reached | `false`
`faults.unready` | when set, the ready state is never reached | `false`
`hpa.enabled` | enables HPA | `false`
`hpa.cpu` | target CPU usage per pod | None
`hpa.memory` | target memory usage per pod | None
`hpa.requests` | target requests per second per pod | None
`hpa.maxReplicas` | maximum pod replicas | `10`
`image.pullPolicy` | image pull policy | `IfNotPresent`
`image.repository` | image repository | `stefanprodan/podinfo`
`image.tag` | image tag | `<VERSION>`
`ingress.enabled` | enables ingress | `false`
`ingress.annotations` | ingress annotations | None
`ingress.hosts` | ingress accepted hostnames | None
`ingress.tls` | ingress TLS configuration | None
`message` | UI greetings message | None
`nodeSelector` | node labels for pod assignment | `{}`
`replicaCount` | desired number of pods | `2`
`resources.requests/cpu` | pod CPU request | `1m`
`resources.requests/memory` | pod memory request | `16Mi`
`resources.limits/cpu` | pod CPU limit | None
`resources.limits/memory` | pod memory limit | None
`service.enabled` | create Kubernetes service (should be disabled when using Flagger) | `true`
`service.metricsPort` | Prometheus metrics endpoint port | `9797`
`service.externalPort` | ClusterIP HTTP port | `9898`
`service.httpPort` | container HTTP port | `9898`
`service.nodePort` | NodePort for the HTTP endpoint | `31198`
`service.grpcPort` | ClusterIP gPRC port | `9999`
`service.grpcService` | gPRC service name | `podinfo`
`service.type` | type of service | `ClusterIP`
`tolerations` | list of node taints to tolerate | `[]`
`serviceAccount.enabled` | specifies whether a service account should be created | `false`
`serviceAccount.name` | the name of the service account to use, if not set and create is true, a name is generated using the fullname template | None
`linkerd.profile.enabled` | create Linkerd service profile | `false`
`replicaCount` | `1` | Desired number of pods
`logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error`, `flat` or `panic`
`backend` | `None` | Echo backend URL
`backends` | `[]` | Array of echo backend URLs
`cache` | `None` | Redis address in the format `<host>:<port>`
`redis.enabled` | `false` | Create Redis deployment for caching purposes
`ui.color` | `#34577c` | UI color
`ui.message` | `None` | UI greetings message
`ui.logo` | `None` | UI logo
`faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds
`faults.error` | `false` | 1/3 chances of a random HTTP response error
`faults.unhealthy` | `false` | When set, the healthy state is never reached
`faults.unready` | `false` | When set, the ready state is never reached
`faults.testFail` | `false` | When set, a helm test is included which always fails
`faults.testTimeout` | `false` | When set, a helm test is included which always times out
`h2c.enabled` | `false` | Allow upgrading to h2c
`image.repository` | `stefanprodan/podinfo` | Image repository
`image.tag` | `<VERSION>` | Image tag
`image.pullPolicy` | `IfNotPresent` | Image pull policy
`service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app)
`service.type` | `ClusterIP` | Type of the Kubernetes Service
`service.metricsPort` | `9797` | Prometheus metrics endpoint port
`service.httpPort` | `9898` | Container HTTP port
`service.externalPort` | `9898` | ClusterIP HTTP port
`service.grpcPort` | `9999` | ClusterIP gPRC port
`service.grpcService` | `podinfo` | gPRC service name
`service.nodePort` | `31198` | NodePort for the HTTP endpoint
`hpa.enabled` | `false` | Enables the Kubernetes HPA
`hpa.maxReplicas` | `10` | Maximum amount of pods
`hpa.cpu` | `None` | Target CPU usage per pod
`hpa.memory` | `None` | Target memory usage per pod
`hpa.requests` | `None` | Target HTTP requests per second per pod
`serviceAccount.enabled` | `false` | Whether a service account should be created
`serviceAccount.name` | `None` | The name of the service account to use, if not set and create is true, a name is generated using the fullname template
`linkerd.profile.enabled` | `false` | Create Linkerd service profile
`serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created
`serviceMonitor.interval` | `15s` | Prometheus scraping interval
`ingress.enabled` | `false` | Enables Ingress
`ingress.annotations` | `{}` | Ingress annotations
`ingress.path` | `/*` | Ingress path
`ingress.hosts` | `[]` | Ingress accepted hosts
`ingress.tls` | `[]` | Ingress TLS configuration
`resources.requests.cpu` | `1m` | Pod CPU request
`resources.requests.memory` | `16Mi` | Pod memory request
`resources.limits.cpu` | `None` | Pod CPU limit
`resources.limits.memory` | `None` | Pod memory limit
`nodeSelector` | `{}` | Node labels for pod assignment
`tolerations` | `[]` | List of node taints to tolerate
`affinity` | `None` | Node/pod affinities
`podAnnotations` | `{}` | Pod annotations
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
```console
$ helm install stable/podinfo --name my-release \
--set=image.tag=0.0.2,service.type=NodePort
$ helm install my-release podinfo/podinfo \
--set=serviceMonitor.enabled=true,serviceMonitor.interval=5s
```
To add custom annotations you need to escape the annotation key string:
```console
$ helm upgrade -i my-release podinfo/podinfo \
--set podAnnotations."appmesh\.k8s\.aws\/preview"=enabled
```
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/podinfo --name my-release -f values.yaml
$ helm install my-release podinfo/podinfo -f values.yaml
```
> **Tip**: You can use the default [values.yaml](values.yaml)
```

View File

@@ -11,9 +11,8 @@
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 "podinfo.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "podinfo.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "podinfo.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:{{ .Values.service.externalPort }}
kubectl -n {{ .Release.Namespace }} port-forward deploy/{{ template "podinfo.fullname" . }} 8080:{{ .Values.service.externalPort }}
{{- end }}

View File

@@ -3,7 +3,7 @@ kind: Deployment
metadata:
name: {{ template "podinfo.fullname" . }}
labels:
app: {{ template "podinfo.name" . }}
app: {{ template "podinfo.fullname" . }}
chart: {{ template "podinfo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
@@ -17,16 +17,17 @@ spec:
maxUnavailable: 1
selector:
matchLabels:
app: {{ template "podinfo.name" . }}
release: {{ .Release.Name }}
app: {{ template "podinfo.fullname" . }}
template:
metadata:
labels:
app: {{ template "podinfo.name" . }}
release: {{ .Release.Name }}
app: {{ template "podinfo.fullname" . }}
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "{{ .Values.service.httpPort }}"
{{- range $key, $value := .Values.podAnnotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
terminationGracePeriodSeconds: 30
{{- if .Values.serviceAccount.enabled }}
@@ -51,6 +52,11 @@ spec:
{{- range .Values.backends }}
- --backend-url={{ . }}
{{- end }}
{{- if .Values.cache }}
- --cache-server={{ .Values.cache }}
{{- else if .Values.redis.enabled }}
- --cache-server={{ template "podinfo.fullname" . }}:6379
{{- end }}
- --level={{ .Values.logLevel }}
- --random-delay={{ .Values.faults.delay }}
- --random-error={{ .Values.faults.error }}
@@ -66,7 +72,7 @@ spec:
env:
{{- if .Values.ui.message }}
- name: PODINFO_UI_MESSAGE
value: {{ .Values.ui.message }}
value: {{ quote .Values.ui.message }}
{{- end }}
{{- if .Values.ui.logo }}
- name: PODINFO_UI_LOGO

View File

@@ -1,7 +1,7 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "podinfo.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}

View File

@@ -61,6 +61,14 @@ spec:
method: GET
pathRegex: /status/[^/]*
name: GET /status/{code}
- condition:
method: POST
pathRegex: /cache
name: POST /cache
- condition:
method: GET
pathRegex: /cache/[^/]*
name: GET /cache/{hash}
- condition:
method: POST
pathRegex: /store

View File

@@ -0,0 +1,12 @@
{{- if .Values.redis.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "podinfo.fullname" . }}-redis
data:
redis.conf: |
maxmemory 64mb
maxmemory-policy allkeys-lru
save ""
appendonly no
{{- end }}

View File

@@ -0,0 +1,68 @@
{{- if .Values.redis.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "podinfo.fullname" . }}-redis
labels:
app: {{ template "podinfo.fullname" . }}-redis
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: {{ template "podinfo.fullname" . }}-redis
template:
metadata:
labels:
app: {{ template "podinfo.fullname" . }}-redis
annotations:
checksum/config: {{ include (print $.Template.BasePath "/redis/config.yaml") . | sha256sum | quote }}
spec:
{{- if .Values.serviceAccount.enabled }}
serviceAccountName: {{ template "podinfo.serviceAccountName" . }}
{{- end }}
containers:
- name: redis
image: "{{ .Values.redis.repository }}:{{ .Values.redis.tag }}"
imagePullPolicy: IfNotPresent
command:
- redis-server
- "/redis-master/redis.conf"
ports:
- name: redis
containerPort: 6379
protocol: TCP
livenessProbe:
tcpSocket:
port: redis
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 1000m
memory: 128Mi
requests:
cpu: 100m
memory: 32Mi
volumeMounts:
- mountPath: /var/lib/redis
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: {{ template "podinfo.fullname" . }}-redis
items:
- key: redis.conf
path: redis.conf
{{- end }}

View File

@@ -0,0 +1,17 @@
{{- if .Values.redis.enabled -}}
apiVersion: v1
kind: Service
metadata:
name: {{ template "podinfo.fullname" . }}-redis
labels:
app: {{ template "podinfo.fullname" . }}-redis
spec:
type: ClusterIP
selector:
app: {{ template "podinfo.fullname" . }}-redis
ports:
- name: redis
port: 6379
protocol: TCP
targetPort: redis
{{- end }}

View File

@@ -25,6 +25,5 @@ spec:
name: grpc
{{- end }}
selector:
app: {{ template "podinfo.name" . }}
release: {{ .Release.Name }}
app: {{ template "podinfo.fullname" . }}
{{- end }}

View File

@@ -0,0 +1,19 @@
{{- if .Values.serviceMonitor.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ template "podinfo.fullname" . }}
labels:
app: {{ template "podinfo.name" . }}
chart: {{ template "podinfo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
endpoints:
- path: /metrics
port: http
interval: {{ .Values.serviceMonitor.interval }}
selector:
matchLabels:
app: {{ template "podinfo.fullname" . }}
{{- end }}

View File

@@ -0,0 +1,32 @@
{{- if .Values.cache }}
apiVersion: v1
kind: Pod
metadata:
name: {{ template "podinfo.fullname" . }}-cache-test-{{ randAlphaNum 5 | lower }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
spec:
containers:
- name: curl
image: curlimages/curl:7.69.0
command:
- sh
- -c
- |
curl -sd 'data' ${PODINFO_SVC}/cache/test &&
curl -s ${PODINFO_SVC}/cache/test | grep data &&
curl -s -XDELETE ${PODINFO_SVC}/cache/test
env:
- name: PODINFO_SVC
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}"
restartPolicy: Never
{{- end }}

View File

@@ -0,0 +1,24 @@
{{- if .Values.faults.testFail }}
apiVersion: v1
kind: Pod
metadata:
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test-success
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
spec:
containers:
- name: fault
image: alpine:3.11
command: ['/bin/sh']
args: ['-c', 'exit 1']
restartPolicy: Never
{{- end }}

View File

@@ -8,7 +8,7 @@ metadata:
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test
"helm.sh/hook": test-success
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled

View File

@@ -8,7 +8,7 @@ metadata:
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test
"helm.sh/hook": test-success
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled
@@ -25,6 +25,5 @@ spec:
curl -sH "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test
env:
- name: PODINFO_SVC
value: {{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}"
restartPolicy: Never

View File

@@ -8,7 +8,7 @@ metadata:
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test
"helm.sh/hook": test-success
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled
@@ -16,7 +16,7 @@ metadata:
spec:
containers:
- name: curl
image: giantswarm/tiny-tools
image: curlimages/curl:7.69.0
command:
- sh
- -c
@@ -24,5 +24,5 @@ spec:
curl -s ${PODINFO_SVC}/api/info | grep version
env:
- name: PODINFO_SVC
value: {{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}
value: "{{ template "podinfo.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.externalPort }}"
restartPolicy: Never

View File

@@ -0,0 +1,24 @@
{{- if .Values.faults.testTimeout }}
apiVersion: v1
kind: Pod
metadata:
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "podinfo.name" . }}
annotations:
"helm.sh/hook": test-success
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
sidecar.istio.io/inject: "false"
linkerd.io/inject: disabled
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
spec:
containers:
- name: fault
image: alpine:3.11
command: ['/bin/sh']
args: ['-c', 'while sleep 3600; do :; done']
restartPolicy: Never
{{- end }}

View File

@@ -15,13 +15,15 @@ faults:
error: false
unhealthy: false
unready: false
testFail: false
testTimeout: false
h2c:
enabled: false
image:
repository: stefanprodan/podinfo
tag: 3.2.1
tag: 4.0.5
pullPolicy: IfNotPresent
service:
@@ -45,6 +47,14 @@ hpa:
# average http requests per second per pod (k8s-prometheus-adapter)
requests:
# Redis address in the format <host>:<port>
cache: ""
# Redis deployment
redis:
enabled: false
repository: redis
tag: 6.0.1
serviceAccount:
# Specifies whether a service account should be created
enabled: false
@@ -56,6 +66,10 @@ linkerd:
profile:
enabled: false
serviceMonitor:
enabled: false
interval: 15s
ingress:
enabled: false
annotations: {}
@@ -81,3 +95,4 @@ tolerations: []
affinity: {}
podAnnotations: {}

View File

@@ -46,6 +46,7 @@ func main() {
fs.Bool("unready", false, "when set, ready state is never reached")
fs.Int("stress-cpu", 0, "number of CPU cores with 100 load")
fs.Int("stress-memory", 0, "MB of data to load into memory")
fs.String("cache-server", "", "Redis address in the format <host>:<port>")
versionFlag := fs.BoolP("version", "v", false, "get version number")

32
deploy/README.md Normal file
View File

@@ -0,0 +1,32 @@
# Deploy demo webapp
Demo webapp manifests:
- [common](webapp/common)
- [frontend](webapp/frontend)
- [backend](webapp/backend)
Deploy the demo in `webapp` namespace:
```bash
kubectl apply -f ./webapp/common
kubectl apply -f ./webapp/backend
kubectl apply -f ./webapp/frontend
```
Deploy the demo in the `dev` namespace:
```bash
kustomize build ./overlays/dev | kubectl apply -f-
```
Deploy the demo in the `staging` namespace:
```bash
kustomize build ./overlays/staging | kubectl apply -f-
```
Deploy the demo in the `production` namespace:
```bash
kustomize build ./overlays/production | kubectl apply -f-
```

View File

@@ -0,0 +1,73 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: backend
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: backend
spec:
containers:
- name: backend
image: stefanprodan/podinfo:4.0.5
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=backend
- --level=info
- --cache-server=cache:6379
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 32Mi

View File

@@ -0,0 +1,18 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: backend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 1
maxReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 99

View File

@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
- deployment.yaml
- hpa.yaml

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
selector:
app: backend
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- port: 9999
targetPort: grpc
protocol: TCP
name: grpc

57
deploy/bases/cache/deployment.yaml vendored Normal file
View File

@@ -0,0 +1,57 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache
spec:
selector:
matchLabels:
app: cache
template:
metadata:
labels:
app: cache
spec:
containers:
- name: redis
image: redis:6.0.1
imagePullPolicy: IfNotPresent
command:
- redis-server
- "/redis-master/redis.conf"
ports:
- name: redis
containerPort: 6379
protocol: TCP
livenessProbe:
tcpSocket:
port: redis
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 1000m
memory: 128Mi
requests:
cpu: 100m
memory: 32Mi
volumeMounts:
- mountPath: /var/lib/redis
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-config
items:
- key: redis.conf
path: redis.conf

9
deploy/bases/cache/kustomization.yaml vendored Normal file
View File

@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
- deployment.yaml
configMapGenerator:
- name: redis-config
files:
- redis.conf

4
deploy/bases/cache/redis.conf vendored Normal file
View File

@@ -0,0 +1,4 @@
maxmemory 64mb
maxmemory-policy allkeys-lru
save ""
appendonly no

13
deploy/bases/cache/service.yaml vendored Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: cache
spec:
type: ClusterIP
selector:
app: cache
ports:
- name: redis
port: 6379
protocol: TCP
targetPort: redis

View File

@@ -0,0 +1,72 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: frontend
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: frontend
spec:
containers:
- name: frontend
image: stefanprodan/podinfo:4.0.5
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --level=info
- --backend-url=http://backend:9898/echo
- --cache-server=cache:6379
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 1000m
memory: 128Mi
requests:
cpu: 100m
memory: 32Mi

View File

@@ -0,0 +1,18 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: frontend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend
minReplicas: 1
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 99

View File

@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
- deployment.yaml
- hpa.yaml

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
protocol: TCP
targetPort: http

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: dev
resources:
- ../../bases/backend
- ../../bases/frontend
- ../../bases/cache
- namespace.yaml
transformers:
- labels.yaml

View File

@@ -0,0 +1,10 @@
apiVersion: builtin
kind: LabelTransformer
metadata:
name: labels
labels:
env: dev
instance: webapp
fieldSpecs:
- path: metadata/labels
create: true

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: dev

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../bases/backend
- ../../bases/frontend
- ../../bases/cache
- namespace.yaml
transformers:
- labels.yaml

View File

@@ -0,0 +1,10 @@
apiVersion: builtin
kind: LabelTransformer
metadata:
name: labels
labels:
env: production
instance: webapp
fieldSpecs:
- path: metadata/labels
create: true

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: production

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: staging
resources:
- ../../bases/backend
- ../../bases/frontend
- ../../bases/cache
- namespace.yaml
transformers:
- labels.yaml

View File

@@ -0,0 +1,10 @@
apiVersion: builtin
kind: LabelTransformer
metadata:
name: labels
labels:
env: staging
instance: webapp
fieldSpecs:
- path: metadata/labels
create: true

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: staging

View File

@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: webapp
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: backend
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: backend
spec:
serviceAccountName: webapp
containers:
- name: backend
image: stefanprodan/podinfo:4.0.5
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=backend
- --level=info
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 32Mi

View File

@@ -0,0 +1,19 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: backend
namespace: webapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 1
maxReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 99

View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: webapp
spec:
type: ClusterIP
selector:
app: backend
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- port: 9999
targetPort: grpc
protocol: TCP
name: grpc

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: webapp

View File

@@ -0,0 +1,29 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: reconciler
namespace: webapp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: reconciler
namespace: webapp
rules:
- apiGroups: ['*']
resources: ['*']
verbs: ['*']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: reconciler
namespace: webapp
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: reconciler
subjects:
- kind: ServiceAccount
name: reconciler
namespace: webapp

View File

@@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: webapp
namespace: webapp

View File

@@ -0,0 +1,73 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: webapp
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: frontend
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: frontend
spec:
serviceAccountName: webapp
containers:
- name: frontend
image: stefanprodan/podinfo:4.0.5
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --level=info
- --backend-url=http://backend:9898/echo
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 1000m
memory: 128Mi
requests:
cpu: 100m
memory: 32Mi

View File

@@ -0,0 +1,19 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: frontend
namespace: webapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 1
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 99

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: webapp
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
protocol: TCP
targetPort: http

View File

@@ -1,35 +0,0 @@
# podinfo end-to-end testing
The e2e testing infrastructure is powered by CircleCI and [Kubernetes Kind](https://github.com/kubernetes-sigs/kind).
### CI workflow
* download go modules
* run unit tests
* build container
* install kubectl, Helm v3 and Kubernetes Kind CLIs
* create local Kubernetes cluster with kind
* load podinfo image onto the local cluster
* deploy podinfo with Helm
* set the podinfo image to the locally built one
* run Helm tests
```yaml
jobs:
e2e-kubernetes:
machine: true
steps:
- checkout
- run:
name: Build podinfo container
command: e2e/build.sh
- run:
name: Start Kubernetes Kind cluster
command: e2e/bootstrap.sh
- run:
name: Install podinfo with Helm
command: e2e/install.sh
- run:
name: Run Helm tests
command: e2e/test.sh
```

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -o errexit
REPO_ROOT=$(git rev-parse --show-toplevel)
KIND_VERSION=v0.7.0
if [[ "$1" ]]; then
KIND_VERSION=$1
fi
echo ">>> Installing kubectl"
curl -sLO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x kubectl && \
sudo mv kubectl /usr/local/bin/
echo ">>> Installing kind"
curl -sSLo kind "https://github.com/kubernetes-sigs/kind/releases/download/$KIND_VERSION/kind-linux-amd64"
chmod +x kind
sudo mv kind /usr/local/bin/kind
echo ">>> Creating kind cluster"
kind create cluster --wait 5m
echo ">>> Installing Helm v3"
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -o errexit
docker build -t test/podinfo:latest .

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
set -o errexit
REPO_ROOT=$(git rev-parse --show-toplevel)
echo '>>> Loading image in Kind'
kind load docker-image test/podinfo:latest
echo '>>> Installing'
helm upgrade -i podinfo ${REPO_ROOT}/charts/podinfo --namespace=default
kubectl set image deployment/podinfo podinfo=test/podinfo:latest
kubectl rollout status deployment/podinfo

View File

@@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -o errexit
function finish {
echo '>>> Test logs'
kubectl logs -l app=podinfo || true
}
trap "finish" EXIT SIGINT
echo '>>> Start integration tests'
helm test podinfo

7
go.mod
View File

@@ -10,17 +10,18 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fatih/color v1.7.0
github.com/fsnotify/fsnotify v1.4.7
github.com/go-chi/chi v4.0.3+incompatible // indirect
github.com/go-chi/chi v4.1.1+incompatible // indirect
github.com/gomodule/redigo v1.8.1
github.com/gorilla/mux v1.7.4
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/go-getter v1.4.1
github.com/prometheus/client_golang v1.5.1
github.com/spf13/cobra v0.0.6
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.2
github.com/swaggo/http-swagger v0.0.0-20190614090009-c2865af9083e
github.com/swaggo/swag v1.6.5
go.uber.org/zap v1.10.0
go.uber.org/zap v1.15.0
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
google.golang.org/grpc v1.23.0
)

38
go.sum
View File

@@ -52,6 +52,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -71,8 +72,8 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/go-chi/chi v4.0.3+incompatible h1:gakN3pDJnzZN5jqFV2TEdF66rTfKeITyR8qu6ekICEY=
github.com/go-chi/chi v4.0.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.1.1+incompatible h1:MmTgB0R8Bt/jccxp+t6S/1VGIKdJw5J74CK/c9tTfA4=
github.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -111,6 +112,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomodule/redigo v1.8.1 h1:Abmo0bI7Xf0IhdIPc7HZQzZcShdnmxeoVuDDtIQp8N8=
github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -123,6 +126,7 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -233,8 +237,11 @@ github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLk
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -248,8 +255,8 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
@@ -268,6 +275,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
@@ -287,6 +296,7 @@ github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
@@ -296,12 +306,21 @@ go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -312,7 +331,10 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -385,8 +407,13 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -421,6 +448,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
@@ -437,4 +465,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@@ -2,8 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
labels:
app: podinfo
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
@@ -25,7 +23,7 @@ spec:
spec:
containers:
- name: podinfod
image: stefanprodan/podinfo:3.2.1
image: stefanprodan/podinfo:4.0.5
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@@ -2,3 +2,6 @@ resources:
- hpa.yaml
- deployment.yaml
- service.yaml
commonLabels:
app: podinfo

View File

@@ -2,8 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: podinfo
labels:
app: podinfo
spec:
type: ClusterIP
selector:

150
pkg/api/cache.go Normal file
View File

@@ -0,0 +1,150 @@
package api
import (
"io/ioutil"
"net/http"
"time"
"github.com/gomodule/redigo/redis"
"github.com/gorilla/mux"
"go.uber.org/zap"
"github.com/stefanprodan/podinfo/pkg/version"
)
// Cache godoc
// @Summary Save payload in cache
// @Description writes the posted content in cache
// @Tags HTTP API
// @Accept json
// @Produce json
// @Router /cache/{key} [post]
// @Success 202
func (s *Server) cacheWriteHandler(w http.ResponseWriter, r *http.Request) {
if s.pool == nil {
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
return
}
key := mux.Vars(r)["key"]
body, err := ioutil.ReadAll(r.Body)
if err != nil {
s.ErrorResponse(w, r, "reading the request body failed", http.StatusBadRequest)
return
}
conn := s.pool.Get()
defer conn.Close()
_, err = conn.Do("SET", key, string(body))
if err != nil {
s.logger.Warn("cache set failed", zap.Error(err))
s.ErrorResponse(w, r, "cache set failed", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusAccepted)
}
// Cache godoc
// @Summary Delete payload from cache
// @Description deletes the key and its value from cache
// @Tags HTTP API
// @Accept json
// @Produce json
// @Router /cache/{key} [delete]
// @Success 202
func (s *Server) cacheDeleteHandler(w http.ResponseWriter, r *http.Request) {
if s.pool == nil {
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
return
}
key := mux.Vars(r)["key"]
conn := s.pool.Get()
defer conn.Close()
_, err := conn.Do("DEL", key)
if err != nil {
s.logger.Warn("cache delete failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusAccepted)
}
// Cache godoc
// @Summary Get payload from cache
// @Description returns the content from cache if key exists
// @Tags HTTP API
// @Accept json
// @Produce json
// @Router /cache/{key} [get]
// @Success 200 {string} string value
func (s *Server) cacheReadHandler(w http.ResponseWriter, r *http.Request) {
if s.pool == nil {
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
return
}
key := mux.Vars(r)["key"]
conn := s.pool.Get()
defer conn.Close()
ok, err := redis.Bool(conn.Do("EXISTS", key))
if err != nil || !ok {
s.logger.Warn("cache key not found", zap.String("key", key))
w.WriteHeader(http.StatusNotFound)
return
}
data, err := redis.String(conn.Do("GET", key))
if err != nil {
s.logger.Warn("cache get failed", zap.Error(err))
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(data))
}
func (s *Server) startCachePool(ticker *time.Ticker, stopCh <-chan struct{}) {
if s.config.CacheServer == "" {
return
}
s.pool = &redis.Pool{
MaxIdle: 3,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", s.config.CacheServer)
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
// set <hostname>=<version> with an expiry time of one minute
setVersion := func() {
conn := s.pool.Get()
if _, err := conn.Do("SET", s.config.Hostname, version.VERSION, "EX", 60); err != nil {
s.logger.Warn("cache server is offline", zap.Error(err), zap.String("server", s.config.CacheServer))
}
_ = conn.Close()
}
// set version on a schedule
go func() {
setVersion()
for {
select {
case <-stopCh:
return
case <-ticker.C:
setVersion()
}
}
}()
}

View File

@@ -1,12 +1,13 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-08-07 15:52:23.918713 +0300 EEST m=+0.023438272
// 2020-05-20 12:48:10.564627 +0300 EEST m=+0.030136350
package docs
import (
"bytes"
"encoding/json"
"strings"
"github.com/alecthomas/template"
"github.com/swaggo/swag"
@@ -16,8 +17,8 @@ var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "Go microservice template for Kubernetes.",
"title": "Podinfo API",
"description": "{{.Description}}",
"title": "{{.Title}}",
"contact": {
"name": "Source Code",
"url": "https://github.com/stefanprodan/podinfo"
@@ -26,10 +27,10 @@ var doc = `{
"name": "MIT License",
"url": "https://github.com/stefanprodan/podinfo/blob/master/LICENSE"
},
"version": "2.0"
"version": "{{.Version}}"
},
"host": "localhost:9898",
"basePath": "/",
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/": {
"get": {
@@ -68,7 +69,6 @@ var doc = `{
"202": {
"description": "Accepted",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -92,13 +92,67 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.RuntimeResponse"
}
}
}
}
},
"/cache/{key}": {
"get": {
"description": "returns the content from cache if key exists",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Get payload from cache",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
},
"post": {
"description": "writes the posted content in cache",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Save payload in cache",
"responses": {
"202": {}
}
},
"delete": {
"description": "deletes the key and its value from cache",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Delete payload from cache",
"responses": {
"202": {}
}
}
},
"/chunked/{seconds}": {
"get": {
"description": "uses transfer-encoding type chunked to give a partial response and then waits for the specified period",
@@ -116,7 +170,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -140,7 +193,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -164,7 +216,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.ArrayResponse"
}
}
@@ -188,7 +239,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.ArrayResponse"
}
}
@@ -333,7 +383,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -357,7 +406,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -404,7 +452,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.TokenResponse"
}
}
@@ -428,7 +475,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.TokenValidationResponse"
}
},
@@ -455,7 +501,6 @@ var doc = `{
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -479,7 +524,6 @@ var doc = `{
"202": {
"description": "Accepted",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -490,11 +534,15 @@ var doc = `{
"definitions": {
"api.ArrayResponse": {
"type": "array",
"items": {}
"items": {
"type": "string"
}
},
"api.MapResponse": {
"type": "object",
"additionalProperties": {}
"additionalProperties": {
"type": "string"
}
},
"api.RuntimeResponse": {
"type": "object",
@@ -511,6 +559,9 @@ var doc = `{
"hostname": {
"type": "string"
},
"logo": {
"type": "string"
},
"message": {
"type": "string"
},
@@ -566,11 +617,21 @@ type swaggerInfo struct {
}
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = swaggerInfo{Schemes: []string{"http", "https"}}
var SwaggerInfo = swaggerInfo{
Version: "2.0",
Host: "localhost:9898",
BasePath: "/",
Schemes: []string{"http", "https"},
Title: "Podinfo API",
Description: "Go microservice template for Kubernetes.",
}
type s struct{}
func (s *s) ReadDoc() string {
sInfo := SwaggerInfo
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
@@ -582,7 +643,7 @@ func (s *s) ReadDoc() string {
}
var tpl bytes.Buffer
if err := t.Execute(&tpl, SwaggerInfo); err != nil {
if err := t.Execute(&tpl, sInfo); err != nil {
return doc
}

View File

@@ -1,4 +1,8 @@
{
"schemes": [
"http",
"https"
],
"swagger": "2.0",
"info": {
"description": "Go microservice template for Kubernetes.",
@@ -53,7 +57,6 @@
"202": {
"description": "Accepted",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -77,13 +80,67 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.RuntimeResponse"
}
}
}
}
},
"/cache/{key}": {
"get": {
"description": "returns the content from cache if key exists",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Get payload from cache",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
},
"post": {
"description": "writes the posted content in cache",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Save payload in cache",
"responses": {
"202": {}
}
},
"delete": {
"description": "deletes the key and its value from cache",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"HTTP API"
],
"summary": "Delete payload from cache",
"responses": {
"202": {}
}
}
},
"/chunked/{seconds}": {
"get": {
"description": "uses transfer-encoding type chunked to give a partial response and then waits for the specified period",
@@ -101,7 +158,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -125,7 +181,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -149,7 +204,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.ArrayResponse"
}
}
@@ -173,7 +227,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.ArrayResponse"
}
}
@@ -318,7 +371,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -342,7 +394,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -389,7 +440,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.TokenResponse"
}
}
@@ -413,7 +463,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.TokenValidationResponse"
}
},
@@ -440,7 +489,6 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -464,7 +512,6 @@
"202": {
"description": "Accepted",
"schema": {
"type": "object",
"$ref": "#/definitions/api.MapResponse"
}
}
@@ -475,11 +522,15 @@
"definitions": {
"api.ArrayResponse": {
"type": "array",
"items": {}
"items": {
"type": "string"
}
},
"api.MapResponse": {
"type": "object",
"additionalProperties": {}
"additionalProperties": {
"type": "string"
}
},
"api.RuntimeResponse": {
"type": "object",
@@ -496,6 +547,9 @@
"hostname": {
"type": "string"
},
"logo": {
"type": "string"
},
"message": {
"type": "string"
},

View File

@@ -1,10 +1,12 @@
basePath: /
definitions:
api.ArrayResponse:
items: {}
items:
type: string
type: array
api.MapResponse:
additionalProperties: {}
additionalProperties:
type: string
type: object
api.RuntimeResponse:
properties:
@@ -16,6 +18,8 @@ definitions:
type: string
hostname:
type: string
logo:
type: string
message:
type: string
num_cpu:
@@ -80,7 +84,6 @@ paths:
description: Accepted
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Echo
tags:
- HTTP API
@@ -96,10 +99,46 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.RuntimeResponse'
type: object
summary: Runtime information
tags:
- HTTP API
/cache/{key}:
delete:
consumes:
- application/json
description: deletes the key and its value from cache
produces:
- application/json
responses:
"202": {}
summary: Delete payload from cache
tags:
- HTTP API
get:
consumes:
- application/json
description: returns the content from cache if key exists
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
summary: Get payload from cache
tags:
- HTTP API
post:
consumes:
- application/json
description: writes the posted content in cache
produces:
- application/json
responses:
"202": {}
summary: Save payload in cache
tags:
- HTTP API
/chunked/{seconds}:
get:
consumes:
@@ -113,7 +152,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Chunked transfer encoding
tags:
- HTTP API
@@ -129,7 +167,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Delay
tags:
- HTTP API
@@ -145,7 +182,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.ArrayResponse'
type: object
summary: Environment
tags:
- HTTP API
@@ -161,7 +197,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.ArrayResponse'
type: object
summary: Headers
tags:
- HTTP API
@@ -257,7 +292,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Status code
tags:
- HTTP API
@@ -274,7 +308,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Upload file
tags:
- HTTP API
@@ -305,7 +338,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.TokenResponse'
type: object
summary: Generate JWT token
tags:
- HTTP API
@@ -321,7 +353,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.TokenValidationResponse'
type: object
"401":
description: Unauthorized
schema:
@@ -339,7 +370,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Version
tags:
- HTTP API
@@ -355,8 +385,10 @@ paths:
description: Accepted
schema:
$ref: '#/definitions/api.MapResponse'
type: object
summary: Echo over websockets
tags:
- HTTP API
schemes:
- http
- https
swagger: "2.0"

View File

@@ -3,11 +3,6 @@ package api
import (
"context"
"fmt"
"github.com/swaggo/swag"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"net/http"
_ "net/http/pprof"
"os"
@@ -15,13 +10,17 @@ import (
"sync/atomic"
"time"
"github.com/gomodule/redigo/redis"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/viper"
_ "github.com/stefanprodan/podinfo/pkg/api/docs"
"github.com/stefanprodan/podinfo/pkg/fscache"
httpSwagger "github.com/swaggo/http-swagger"
"github.com/swaggo/swag"
"go.uber.org/zap"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
// @title Podinfo API
@@ -44,11 +43,6 @@ var (
watcher *fscache.Watcher
)
type FluxConfig struct {
GitUrl string `mapstructure:"git-url"`
GitBranch string `mapstructure:"git-branch"`
}
type Config struct {
HttpClientTimeout time.Duration `mapstructure:"http-client-timeout"`
HttpServerTimeout time.Duration `mapstructure:"http-server-timeout"`
@@ -69,12 +63,14 @@ type Config struct {
Unhealthy bool `mapstructure:"unhealthy"`
Unready bool `mapstructure:"unready"`
JWTSecret string `mapstructure:"jwt-secret"`
CacheServer string `mapstructure:"cache-server"`
}
type Server struct {
router *mux.Router
logger *zap.Logger
config *Config
pool *redis.Pool
}
func NewServer(config *Config, logger *zap.Logger) (*Server, error) {
@@ -103,8 +99,11 @@ func (s *Server) registerHandlers() {
s.router.HandleFunc("/readyz/disable", s.disableReadyHandler).Methods("POST")
s.router.HandleFunc("/panic", s.panicHandler).Methods("GET")
s.router.HandleFunc("/status/{code:[0-9]+}", s.statusHandler).Methods("GET", "POST", "PUT").Name("status")
s.router.HandleFunc("/store", s.storeWriteHandler).Methods("POST")
s.router.HandleFunc("/store", s.storeWriteHandler).Methods("POST", "PUT")
s.router.HandleFunc("/store/{hash}", s.storeReadHandler).Methods("GET").Name("store")
s.router.HandleFunc("/cache/{key}", s.cacheWriteHandler).Methods("POST", "PUT")
s.router.HandleFunc("/cache/{key}", s.cacheDeleteHandler).Methods("DELETE")
s.router.HandleFunc("/cache/{key}", s.cacheReadHandler).Methods("GET").Name("cache")
s.router.HandleFunc("/configs", s.configReadHandler).Methods("GET")
s.router.HandleFunc("/token", s.tokenGenerateHandler).Methods("POST")
s.router.HandleFunc("/token/validate", s.tokenValidateHandler).Methods("GET")
@@ -176,6 +175,10 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
}
}
// start redis connection pool
ticker := time.NewTicker(30 * time.Second)
s.startCachePool(ticker, stopCh)
// run server in background
go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
@@ -200,6 +203,11 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
atomic.StoreInt32(&healthy, 0)
atomic.StoreInt32(&ready, 0)
// close cache pool
if s.pool != nil {
_ = s.pool.Close()
}
s.logger.Info("Shutting down HTTP server", zap.Duration("timeout", s.config.HttpServerShutdownTimeout))
// wait for Kubernetes readiness probe to remove this instance from the load balancer

View File

@@ -8,6 +8,7 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/reflection"
)
type Server struct {
@@ -37,6 +38,7 @@ func (s *Server) ListenAndServe() {
srv := grpc.NewServer()
server := health.NewServer()
reflection.Register(srv)
grpc_health_v1.RegisterHealthServer(srv, server)
server.SetServingStatus(s.config.ServiceName, grpc_health_v1.HealthCheckResponse_SERVING)

View File

@@ -1,4 +1,4 @@
package version
var VERSION = "3.2.1"
var VERSION = "4.0.5"
var REVISION = "unknown"