-
Notifications
You must be signed in to change notification settings - Fork 381
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
Add scaffolding to stand up Trillian on k8s. #2754
base: master
Are you sure you want to change the base?
Changes from all commits
9bafa5b
03ecc4f
b7d95be
d7c4370
5177416
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
name: Kind scaffolding test | ||
|
||
on: | ||
pull_request: | ||
branches: [ 'main', 'release-*' ] | ||
|
||
permissions: read-all | ||
|
||
jobs: | ||
e2e-tests: | ||
name: test tree creation with scaffolding | ||
runs-on: ubuntu-latest | ||
|
||
strategy: | ||
fail-fast: false # Keep running if one leg fails. | ||
matrix: | ||
k8s-version: | ||
- v1.22.x | ||
- v1.23.x | ||
- v1.24.x | ||
- v1.25.x | ||
|
||
env: | ||
REGISTRY_NAME: registry.local | ||
REGISTRY_PORT: 5000 | ||
KO_DOCKER_REPO: registry.local:5000/trillian | ||
|
||
steps: | ||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v2.4.0 | ||
- uses: actions/setup-go@b22fbbc2921299758641fab08929b4ac52b32923 # v2.2.0 | ||
with: | ||
go-version: '1.19' | ||
check-latest: true | ||
|
||
- uses: ko-build/[email protected] | ||
|
||
- name: Install yq | ||
uses: mikefarah/yq@70403375d7b96075bd68b40c434807cff1593568 # v4.25.1 | ||
|
||
- name: Setup mirror | ||
uses: chainguard-dev/actions/setup-mirror@main | ||
with: | ||
mirror: mirror.gcr.io | ||
Comment on lines
+40
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the purpose of this mirror? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In some cases esp. in test environments this can reduce flakiness by not hitting rate limits on pulling containers. So by default we set this up before having to add it later :) |
||
|
||
- name: Setup kind cluster | ||
uses: chainguard-dev/actions/setup-kind@main | ||
with: | ||
k8s-version: ${{ matrix.k8s-version }} | ||
cluster-suffix: c${{ github.run_id }}.local | ||
|
||
- name: Setup knative | ||
uses: chainguard-dev/actions/setup-knative@main | ||
with: | ||
k8s-version: ${{ matrix.k8s-version }} | ||
cluster-suffix: c${{ github.run_id }}.local | ||
|
||
- name: Install Trillian | ||
run: | | ||
echo '::group:: install Trillian scaffolding' | ||
ko apply -BRf ./examples/deployment/kubernetes/scaffolding | ||
vaikas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
echo '::endgroup::' | ||
echo '::group:::' waiting for services to come up | ||
kubectl wait -n trillian-system --for=condition=Ready --timeout=5m ksvc --all | ||
echo '::endgroup::' | ||
|
||
- name: Create a tree on it | ||
run: | | ||
echo '::group:: install create tree job' | ||
kubectl apply -Rf ./examples/deployment/kubernetes/createtree | ||
echo '::endgroup::' | ||
echo '::group:::' waiting for job to complete' | ||
kubectl wait -n createtree --for=condition=Complete --timeout=5m jobs createtree | ||
echo '::endgroup::' | ||
kubectl -n createtree get cm trillian-tree -ojsonpath='{.data.treeID}' | ||
|
||
- name: Collect diagnostics | ||
if: ${{ failure() }} | ||
uses: chainguard-dev/actions/kind-diag@84c993eaf02da1c325854fb272a4df9184bd80fc # main |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Copyright 2023 Google LLC. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package main contains the implementation and entry point for the | ||
// creating a tree in Trillian and adding it into a ConfigMap. | ||
// More details and use cases are in: | ||
// ../../examples/deployment/kubernetes/README-SCAFFOLDING.md | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/google/trillian" | ||
"github.com/google/trillian/client" | ||
"github.com/google/trillian/client/rpcflags" | ||
"github.com/pkg/errors" | ||
"google.golang.org/grpc" | ||
"google.golang.org/protobuf/types/known/durationpb" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
"k8s.io/client-go/rest" | ||
"knative.dev/pkg/logging" | ||
"knative.dev/pkg/signals" | ||
"sigs.k8s.io/release-utils/version" | ||
) | ||
|
||
const ( | ||
// Key in the configmap holding the value of the tree. | ||
treeKey = "treeID" | ||
) | ||
|
||
var ( | ||
ns = flag.String("namespace", "", "Namespace where to update the configmap in") | ||
cmname = flag.String("configmap", "", "Name of the configmap where the treeID lives") | ||
adminServerAddr = flag.String("admin_server", "log-server.trillian-system.svc:80", "Address of the gRPC Trillian Admin Server (host:port)") | ||
treeState = flag.String("tree_state", trillian.TreeState_ACTIVE.String(), "State of the new tree") | ||
treeType = flag.String("tree_type", trillian.TreeType_LOG.String(), "Type of the new tree") | ||
displayName = flag.String("display_name", "", "Display name of the new tree") | ||
description = flag.String("description", "", "Description of the new tree") | ||
maxRootDuration = flag.Duration("max_root_duration", time.Hour, "Interval after which a new signed root is produced despite no submissions; zero means never") | ||
force = flag.Bool("force", false, "Force create a new tree and update configmap") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
ctx := signals.NewContext() | ||
if *ns == "" { | ||
logging.FromContext(ctx).Fatal("Need to specify --namespace for where to update the configmap in") | ||
} | ||
if *cmname == "" { | ||
logging.FromContext(ctx).Fatal("Need to specify --configmap for which configmap to update") | ||
} | ||
|
||
versionInfo := version.GetVersionInfo() | ||
logging.FromContext(ctx).Infof("running Version: %s GitCommit: %s BuildDate: %s", versionInfo.GitVersion, versionInfo.GitCommit, versionInfo.BuildDate) | ||
|
||
config, err := rest.InClusterConfig() | ||
if err != nil { | ||
logging.FromContext(ctx).Fatalf("Failed to get InClusterConfig: %v", err) | ||
} | ||
clientset, err := kubernetes.NewForConfig(config) | ||
if err != nil { | ||
logging.FromContext(ctx).Fatalf("Failed to get clientset: %v", err) | ||
} | ||
cm, err := clientset.CoreV1().ConfigMaps(*ns).Get(ctx, *cmname, metav1.GetOptions{}) | ||
if err != nil { | ||
logging.FromContext(ctx).Fatalf("Failed to get the configmap %s/%s: %v", *ns, *cmname, err) | ||
} | ||
|
||
if cm.Data == nil { | ||
cm.Data = make(map[string]string) | ||
} | ||
if treeID, ok := cm.Data[treeKey]; ok && !*force { | ||
logging.FromContext(ctx).Infof("Found existing TreeID: %s", treeID) | ||
return | ||
} | ||
|
||
tree, err := createTree(ctx) | ||
if err != nil { | ||
logging.FromContext(ctx).Fatalf("Failed to create the trillian tree: %v", err) | ||
} | ||
cm.Data[treeKey] = fmt.Sprint(tree.TreeId) | ||
logging.FromContext(ctx).Infof("Created a new tree %d updating configmap %s/%s", tree.TreeId, *ns, *cmname) | ||
|
||
_, err = clientset.CoreV1().ConfigMaps(*ns).Update(ctx, cm, metav1.UpdateOptions{}) | ||
if err != nil { | ||
logging.FromContext(ctx).Fatalf("Failed to update the configmap: %v", err) | ||
} | ||
} | ||
|
||
func createTree(ctx context.Context) (*trillian.Tree, error) { | ||
req, err := newRequest(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
dialOpts, err := rpcflags.NewClientDialOptionsFromFlags() | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to determine dial options") | ||
} | ||
|
||
conn, err := grpc.Dial(*adminServerAddr, dialOpts...) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to dial") | ||
} | ||
defer conn.Close() | ||
|
||
adminClient := trillian.NewTrillianAdminClient(conn) | ||
logClient := trillian.NewTrillianLogClient(conn) | ||
|
||
return client.CreateAndInitTree(ctx, req, adminClient, logClient) | ||
} | ||
|
||
func newRequest(ctx context.Context) (*trillian.CreateTreeRequest, error) { | ||
ts, ok := trillian.TreeState_value[*treeState] | ||
if !ok { | ||
return nil, fmt.Errorf("unknown TreeState: %v", *treeState) | ||
} | ||
|
||
tt, ok := trillian.TreeType_value[*treeType] | ||
if !ok { | ||
return nil, fmt.Errorf("unknown TreeType: %v", *treeType) | ||
} | ||
|
||
ctr := &trillian.CreateTreeRequest{Tree: &trillian.Tree{ | ||
TreeState: trillian.TreeState(ts), | ||
TreeType: trillian.TreeType(tt), | ||
DisplayName: *displayName, | ||
Description: *description, | ||
MaxRootDuration: durationpb.New(*maxRootDuration), | ||
}} | ||
logging.FromContext(ctx).Infof("Creating Tree: %+v", ctr.Tree) | ||
|
||
return ctr, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Deploying onto Kubernetes | ||
|
||
This document guides you through the process of spinning up an example Trillian | ||
deployment on Kubernetes cluster with [Knative](https://knative.dev/docs/) | ||
installed. It's suitable for GitHub action based e2e tests | ||
as well as local testing using something like kind cluster. | ||
|
||
## Prerequisites | ||
|
||
1. You should have this repo checked out :) | ||
1. A Kubernetes cluster with [Knative](https://knative.dev/docs/) installed. One | ||
example for installing local kind cluster with Knative is | ||
[here](https://github.com/sigstore/scaffolding/blob/main/getting-started.md#running-locally-on-kind) | ||
and ignoring the sigstore parts after installing the cluster. | ||
1. [ko](https://github.com/google/ko) installed. | ||
1. You have `kubectl` installed. | ||
|
||
## Process | ||
|
||
1. Create the scaffolding parts of the Trillian system. | ||
```shell | ||
kubectl apply -Rf ./examples/deployment/kubernetes/scaffolding | ||
``` | ||
This spins up a namespace `trillian-system` where it deploys | ||
the following components: | ||
* log-signer | ||
* log-server | ||
* mysql server | ||
2. Let's make sure everything comes up ready: | ||
mhutchinson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```shell | ||
kubectl wait -n trillian-system --for=condition=Ready --timeout=5m ksvc --all | ||
``` | ||
|
||
You should see something like this: | ||
```shell | ||
vaikas@villes-mbp scaffolding % kubectl wait -n trillian-system --for=condition=Ready --timeout=5m ksvc --all | ||
service.serving.knative.dev/log-server condition met | ||
service.serving.knative.dev/log-signer condition met | ||
``` | ||
3. Then create a tree in the Trillian: | ||
```shell | ||
ko apply -BRf ./examples/deployment/kubernetes/createtree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to add an issue (assigned to me) and TODO here to swap this over to use a pre-built image so that ko isn't needed. |
||
``` | ||
|
||
And make sure it completes. | ||
|
||
```shell | ||
kubectl wait -n createtree --for=condition=Complete --timeout=5m jobs createtree | ||
``` | ||
|
||
4. Check out the tree: | ||
```shell | ||
kubectl -n createtree get cm trillian-tree -ojsonpath='{.data.treeID}' | ||
``` | ||
|
||
You should see something like this: | ||
```shell | ||
vaikas@villes-mbp scaffolding % kubectl -n createtree get cm trillian-tree -ojsonpath='{.data.treeID}' | ||
5213139395739357930% | ||
``` | ||
|
||
5. You can then use the TreeID for example to run CTLog on | ||
top of newly created Trillian. | ||
|
||
6. TODO: Add examples for talking to Trillian for other things. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
kind: Namespace | ||
apiVersion: v1 | ||
metadata: | ||
name: createtree |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: Role | ||
metadata: | ||
namespace: createtree | ||
name: cm-operator | ||
rules: | ||
- apiGroups: [""] # "" indicates the core API group | ||
resources: ["configmaps"] | ||
resourceNames: ["trillian-tree"] | ||
verbs: ["get", "update"] | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: RoleBinding | ||
metadata: | ||
name: role-cm-updater | ||
namespace: createtree | ||
roleRef: | ||
apiGroup: rbac.authorization.k8s.io | ||
kind: Role | ||
name: cm-operator | ||
subjects: | ||
- kind: ServiceAccount | ||
name: createtree | ||
namespace: createtree |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
apiVersion: v1 | ||
kind: ConfigMap | ||
metadata: | ||
name: trillian-tree | ||
namespace: createtree | ||
data: | ||
__placeholder: | | ||
################################################################### | ||
# Just a placeholder so that reapplying this won't overwrite treeID | ||
# if it already exists. This caused grief, do not remove. | ||
################################################################### | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: createtree | ||
namespace: createtree |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
apiVersion: batch/v1 | ||
kind: Job | ||
metadata: | ||
name: createtree | ||
namespace: createtree | ||
spec: | ||
template: | ||
spec: | ||
serviceAccountName: createtree | ||
restartPolicy: Never | ||
containers: | ||
- name: createtree | ||
image: ko://github.com/google/trillian/cmd/createtree-k8s | ||
args: [ | ||
"--namespace=createtree", | ||
"--configmap=trillian-tree", | ||
"--display_name=ctlogtree" | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
kind: Namespace | ||
apiVersion: v1 | ||
metadata: | ||
name: trillian-system |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to add newer kube versions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL, oh dear :) Yes, done.