Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump actions, fix cache, move to chainguard, simplify docker flow #47

Merged
merged 29 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 93 additions & 102 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,41 @@ on:
branches:
- main

env:
IMAGE: clux/controller

jobs:
docker:
docker-base:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Prepare image tags
id: prep
run: |
TAG=$(grep -E "^version" Cargo.toml | awk -F"\"" '{print $2}' | head -n 1)
IMAGE="${{ env.IMAGE }}"
if curl -sSL https://registry.hub.docker.com/v1/repositories/${IMAGE}/tags | jq -r ".[].name" | grep -q ${TAG}; then
echo "Semver tag ${TAG} already exists - not publishing"
echo ::set-output name=tagsbase::${IMAGE}:latest
echo ::set-output name=tagsotel::${IMAGE}:otel
else
echo "Semver tag ${TAG} not found - publishing"
echo ::set-output name=tagsbase::${IMAGE}:latest,${IMAGE}:${TAG}
echo ::set-output name=tagsotel::${IMAGE}:otel,${IMAGE}:otel-${TAG}
fi
echo ::set-output name=semver::${TAG}
- uses: actions/checkout@v3

- uses: docker/setup-buildx-action@v1
id: buildx
# Build and push with docker buildx
- name: Setup docker buildx
uses: docker/setup-buildx-action@v2

- name: Inspect builder
run: |
echo "Name: ${{ steps.buildx.outputs.name }}"
echo "Endpoint: ${{ steps.buildx.outputs.endpoint }}"
echo "Status: ${{ steps.buildx.outputs.status }}"
echo "Flags: ${{ steps.buildx.outputs.flags }}"
echo "Platforms: ${{ steps.buildx.outputs.platforms }}"

- uses: docker/metadata-action@v3
id: docker_meta
with:
images: ${{ env.IMAGE }}
labels: |
org.opencontainers.image.version=${{ steps.prep.outputs.semver }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.title=${{ env.IMAGE }}

- uses: docker/login-action@v1
- name: Configure tags based on git tags + latest
uses: docker/metadata-action@v4
id: meta
with:
images: clux/controller
tags: |
type=pep440,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=pr

- name: Docker login on main origin
uses: docker/login-action@v2
if: github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-dockerx6-${{ steps.prep.outputs.semver }}
restore-keys: |
${{ runner.os }}-dockerx6-

- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git
target
key: musl-cargo-${{ hashFiles('**/Cargo.toml') }}

~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: musl-cargo-${{ hashFiles('**/Cargo.lock') }}

- name: Compile base features
run: |
Expand All @@ -82,38 +50,63 @@ jobs:
--mount type=bind,source=$HOME/.cargo/registry,target=/root/.cargo/registry \
--mount type=bind,source=$HOME/.cargo/git,target=/root/.cargo/git \
clux/muslrust:stable \
cargo build --release
cargo build --release --bin controller
cp target/x86_64-unknown-linux-musl/release/controller .

- name: Build and push controller image with base features
uses: docker/build-push-action@v2
- name: Docker buildx and push with base features
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
platforms: linux/amd64
cache-from: type=gha,scope=base
cache-to: type=gha,scope=base,mode=max
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ steps.prep.outputs.tagsbase }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=gha,scope=version5
cache-to: type=gha,scope=version5,mode=max

tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64

- name: Persist base image build to a tarball
uses: docker/build-push-action@v2
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
platforms: linux/amd64
tags: ${{ steps.prep.outputs.tagsbase }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=gha,scope=version5
cache-to: type=gha,scope=version5,mode=max
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha,scope=base
outputs: type=docker,dest=/tmp/image.tar

- name: Upload base docker image as artifact for e2e tests
uses: actions/upload-artifact@v3
with:
name: controller-image
path: /tmp/image.tar

docker-otel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

# Build and push with docker buildx
- name: Setup docker buildx
uses: docker/setup-buildx-action@v2

- name: Configure tags based on git tags for otel
uses: docker/metadata-action@v4
id: meta
with:
images: clux/controller
tags: |
type=pep440,pattern={{version}},prefix=otel-
type=raw,value=otel,enable={{is_default_branch}}
type=ref,event=pr,prefix=otel-

- uses: actions/cache@v3
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: musl-cargo-otel-${{ hashFiles('**/Cargo.lock') }}

- name: Compile with telemetry
run: |
mkdir -p ~/.cargo/{git,registry}
Expand All @@ -122,26 +115,32 @@ jobs:
--mount type=bind,source=$HOME/.cargo/registry,target=/root/.cargo/registry \
--mount type=bind,source=$HOME/.cargo/git,target=/root/.cargo/git \
clux/muslrust:stable \
cargo build --features=telemetry --release
cargo build --features=telemetry --release --bin controller
cp target/x86_64-unknown-linux-musl/release/controller .

- name: Build and push controller image with telemetry
uses: docker/build-push-action@v2
- name: Docker login on main origin
uses: docker/login-action@v2
if: github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Docker buildx and push with telemetry
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
platforms: linux/amd64
cache-from: type=gha,scope=otel
cache-to: type=gha,scope=otel,mode=max
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ steps.prep.outputs.tagsotel }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=gha,scope=version5
cache-to: type=gha,scope=version5,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64

e2e:
runs-on: ubuntu-latest
needs: [docker]
needs: [docker-base]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: nolar/setup-k3d-k3s@v1
with:
version: v1.25
Expand All @@ -168,30 +167,26 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install protoc
run: sudo apt-get install -y protobuf-compiler
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
components: rustfmt,clippy
override: true
- name: Run rustfmt
run: cargo +nightly fmt -- --check
- uses: actions-rs/clippy-check@v1
- run: cargo +nightly fmt -- --check

- uses: giraffate/clippy-action@v1
with:
args: --all-features
token: ${{ secrets.GITHUB_TOKEN }}
reporter: 'github-pr-review'
github_token: ${{ secrets.GITHUB_TOKEN }}
clippy_flags: --all-features

integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
override: true
toolchain: stable
profile: minimal
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: nolar/setup-k3d-k3s@v1
with:
Expand All @@ -209,14 +204,10 @@ jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 2
- uses: actions-rs/toolchain@v1
with:
override: true
toolchain: stable
profile: minimal
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2

# Real CI work starts here
Expand Down
13 changes: 4 additions & 9 deletions .github/workflows/rustfmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install nightly toolchain with rustfmt available
uses: actions-rs/toolchain@v1
uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
override: true
components: rustfmt

- run: rustfmt +nightly --edition 2018 $(find . -type f -iname *.rs)
- run: cargo +nightly fmt

- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
commit-message: rustfmt
signoff: true
title: rustfmt
body: |
Changes from `rustfmt +nightly --edition 2018 $(find . -type f -iname *.rs)`.
body: Changes from `cargo +nightly fmt`.
branch: rustfmt
# Delete branch when merged
delete-branch: true
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ opentelemetry = { version = "0.18.0", features = ["trace", "rt-tokio"] }
opentelemetry-otlp = { version = "0.11.0", features = ["tokio"], optional = true }
tonic = { version = "0.8.3", optional = true }
thiserror = "1.0.37"
anyhow = "1.0.69"

[dev-dependencies]
assert-json-diff = "2.0.2"
Expand Down
5 changes: 1 addition & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
FROM gcr.io/distroless/static:nonroot
LABEL org.opencontainers.image.source=https://github.com/kube-rs/controller-rs
LABEL org.opencontainers.image.description="Kube Example Controller"
LABEL org.opencontainers.image.licenses="Apache-2.0"
FROM cgr.dev/chainguard/static
COPY --chown=nonroot:nonroot ./controller /app/
EXPOSE 8080
ENTRYPOINT ["/app/controller"]
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ OPENTELEMETRY_ENDPOINT_URL=https://0.0.0.0:55680 RUST_LOG=info,kube=trace,contro
```

### In-cluster
Use either your locally built image or the one from dockerhub (using opentemetry features by default). Edit the [deployment](./yaml/deployment.yaml)'s image tag appropriately, and then:
Use either your locally built image or the one from dockerhub (using opentelemetry features by default). Edit the [deployment](./yaml/deployment.yaml)'s image tag appropriately, and then:

```sh
kubectl apply -f yaml/deployment.yaml
Expand All @@ -60,8 +60,6 @@ kubectl port-forward service/doc-controller 8080:80

To build and deploy the image quickly, we recommend using [tilt](https://tilt.dev/), via `tilt up` instead.

**NB**: namespace is assumed to be `default`. If you need a different namespace, you can replace `default` with whatever you want in the yaml and set the namespace in your current-context to get all the commands here to work.

## Usage
In either of the run scenarios, your app is listening on port `8080`, and it will observe `Document` events.

Expand Down Expand Up @@ -104,9 +102,9 @@ $ curl 0.0.0.0:8080/
{"last_event":"2019-07-17T22:31:37.591320068Z"}
```

The metrics will be auto-scraped if you have a standard [`PodMonitor` for `prometheus.io/scrape`](https://github.com/prometheus-community/helm-charts/blob/b69e89e73326e8b504102a75d668dc4351fcdb78/charts/prometheus/values.yaml#L1608-L1650).
The metrics will be scraped by prometheus if you setup a `PodMonitor` or `ServiceMonitor` for it.

### Events
The example `reconciler` only checks the `.spec.hidden` bool. If it does, it updates the `.status` object to reflect whether or not the instance `is_hidden`. It also sends a kubernetes event associated with the controller. It is visible at the bottom of `kubectl describe doc samuel`.
The example `reconciler` only checks the `.spec.hidden` bool. If it does, it updates the `.status` object to reflect whether or not the instance `is_hidden`. It also sends a Kubernetes event associated with the controller. It is visible at the bottom of `kubectl describe doc samuel`.

While this controller has no child objects configured, there is a [`configmapgen_controller`](https://github.com/kube-rs/kube/blob/main/examples/configmapgen_controller.rs) example in [kube-rs](https://github.com/kube-rs/kube/).
To extend this controller for a real-world setting. Consider looking at the [kube.rs controller guide](https://kube.rs/controllers/intro/).
Loading