Getting Started Pt 3

Getting Started with Autopilot Part 3 - Deploying the Operator

In part 3 of the Getting Started tutorial for AutoPilot, we’ll deploy and test our changes from part 2.

To see the completed code for this tutorial, check out https://github.com/solo-io/autorouter

About

Tutorial

Prerequisites

Build the Operator

Just like we did in part 1, let’s build and deploy the operator. Notice we deploy with the -d flag which tells Kubernetes to delete the existing operator pod (to trigger a fresh image pull)

ap build <image>
ap deploy <image> -p -d

We should see that our pod is running:

kubectl get pod -n autoroute-operator
NAME                                 READY   STATUS    RESTARTS   AGE
autoroute-operator-ccbd545c6-bb2s7   1/1     Running   0          1m

If you’ve still got the AutoRoute we deployed in part 1, you’ll notice that the pod is no longer in a CrashLoop. This is a good start. If you don’t have the “example” AutoRoute, deploy it again:

kubectl create ns example 
kubectl apply -n example -f deploy/autoroute_example.yaml

Let’s take a look at our logs again:

ap logs
{"level":"info","ts":1573835381.23586,"logger":"controller-runtime.metrics","msg":"metrics server is starting to listen","addr":":9091"}
{"level":"info","ts":1573835381.2361934,"msg":"Registering watch for primary resource AutoRoute"}
{"level":"info","ts":1573835381.2362459,"logger":"controller-runtime.controller","msg":"Starting EventSource","controller":"autoRoute-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1573835381.2364664,"msg":"Registering watch for output resource Services"}
{"level":"info","ts":1573835381.236519,"logger":"controller-runtime.controller","msg":"Starting EventSource","controller":"autoRoute-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1573835381.2366421,"msg":"Registering watch for output resource VirtualServices"}
{"level":"info","ts":1573835381.2366784,"logger":"controller-runtime.controller","msg":"Starting EventSource","controller":"autoRoute-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1573835381.2367713,"msg":"Registering watch for output resource Gateways"}
{"level":"info","ts":1573835381.2368004,"logger":"controller-runtime.controller","msg":"Starting EventSource","controller":"autoRoute-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1573835381.2370074,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"}
{"level":"info","ts":1573835397.8720093,"logger":"controller-runtime.controller","msg":"Starting Controller","controller":"autoRoute-controller"}
{"level":"info","ts":1573835397.9722834,"logger":"controller-runtime.controller","msg":"Starting workers","controller":"autoRoute-controller","worker count":1}
{"level":"info","ts":1573835743.5527482,"msg":"Syncing AutoRoute in phase Initializing","autoRoute":"example.example","phase":"","name":"example"}
{"level":"info","ts":1573835743.55888,"msg":"Syncing AutoRoute in phase Syncing","autoRoute":"example.example","phase":"Syncing","name":"example"}
{"level":"info","ts":1573835743.6597307,"msg":"cycle through each deployment and check that the labels match our selector","autoRoute":"example.example","phase":"Syncing"}
{"level":"info","ts":1573835743.6598568,"msg":"ensuring the gateway, services and virtual service outputs are created","autoRoute":"example.example","phase":"Syncing","status":{"syncedDeployments":null},"gateway":"example","virtual services":0,"kube services":0}
{"level":"info","ts":1573835743.6726131,"msg":"Updating status of primary resource","autoRoute":"example.example","phase":"Syncing"}
{"level":"info","ts":1573835743.6782513,"msg":"Syncing AutoRoute in phase Ready","autoRoute":"example.example","phase":"Ready","name":"example"}
{"level":"info","ts":1573835743.67874,"msg":"cycle through each deployment and check that the labels match our selector","autoRoute":"example.example","phase":"Ready"}

Now we see that our operator processed the AutoRoute. The AutoRoute was synced and is now in state ready:

kubectl get autoroute -n example -oyaml example
apiVersion: examples.io/v1
kind: AutoRoute
metadata:
  creationTimestamp: "2019-11-15T16:35:43Z"
  generation: 1
  labels:
    app: autoroute-operator
    app.kubernetes.io/name: autoroute-operator
  name: example
  namespace: example
  resourceVersion: "394326"
  selfLink: /apis/examples.io/v1/namespaces/example/autoroutes/example
  uid: f7cba80e-07c5-11ea-beb2-42010a8e0142
status:
  observedGeneration: 1
  phase: Ready
  syncedDeployments: null

We should also see that our operator created a Gateway:

kubectl get gateways.networking.istio.io -n example
NAME      AGE
example   11m

We expect no Virtual Services or Kube Services to be created yet. Let’s create a few deployments to see them get spun up:

for i in 1 2 3; do 
cat <<EOF | kubectl apply -n example -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-${i}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin-${i}
  template:
    metadata:
      labels:
        app: httpbin-${i}
    spec:
      containers:
        - image: docker.io/kennethreitz/httpbin
          imagePullPolicy: IfNotPresent
          name: httpbin
          ports:
            - containerPort: 80
EOF
done
deployment.apps/httpbin-1 created
deployment.apps/httpbin-2 created
deployment.apps/httpbin-3 created

If everything worked, we should immediately be able to hit these deployments with traffic! Let’s try it out.

First, we need the IP:PORT of the Istio Ingress. The way we reach this depends on your environment setup

Finally, send some requests using curl:

curl -I -HHost:httpbin-1.example http://$INGRESS_HOST:$INGRESS_PORT/status/200
curl -I -HHost:httpbin-2.example http://$INGRESS_HOST:$INGRESS_PORT/status/200
curl -I -HHost:httpbin-3.example http://$INGRESS_HOST:$INGRESS_PORT/status/200

All 3 of our services should reply with HTTP/1.1 200 OK:

HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 15 Nov 2019 17:34:05 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 1

Awesome! We’ve just automated our Istio ingress with Autopilot!

We can see that the AutoRoute automatically created some Istio Virtual Serivces:

kubectl get virtualservices.networking.istio.io -n example
NAME                GATEWAYS    HOSTS                 AGE
httpbin-1.example   [example]   [httpbin-1.example]   2m
httpbin-2.example   [example]   [httpbin-2.example]   2m
httpbin-3.example   [example]   [httpbin-3.example]   2m

As well as standard Kube services:

kubectl get svc -n example
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
httpbin-1   ClusterIP   10.3.252.230   <none>        80/TCP    4m51s
httpbin-2   ClusterIP   10.3.243.217   <none>        80/TCP    4m51s
httpbin-3   ClusterIP   10.3.253.81    <none>        80/TCP    4m51s

Tearing down

To tear down the example environment:

kubectl delete ns example
kubectl delete ns autorouter-operator
kubectl delete crd autoroutes.examples.io

Summary

This guide provides a demonstration on how Autopilot can be used to automate Mesh features. For a more robust, real-world example, see the Autopilot Canary Project, which is used as an automated end-to-end test for Autopilot.

Please submit questions and feedback to the solo.io slack channel, or open an issue on GitHub.