# Source to URL - Go A sample that shows how to use Knative to go from source code in a git repository to a running application with a URL. This sample uses Go. This sample uses the [Build](../../../build/README.md) and [Serving](../../README.md) components of Knative to orchestrate an end-to-end deployment. ## Prerequisites * A Kubernetes cluster with Knative installed. Follow the [installation instructions](https://github.com/knative/docs/blob/master/install/README.md) if you need to create one. * Go installed and configured (optional, if you want to run the sample app locally). ## Configuring Knative To use this sample, a few configuration steps are required before we can deploy. You need to install a [Build Template](https://github.com/knative/build-templates) that will be used by the sample, and register a secret for your container registry. In this example, we'll use Docker Hub. ### Install kaniko build template This sample leverages the [kaniko build template](https://github.com/knative/build-templates/tree/master/kaniko) to perform a source-to-container build on the Kubernetes cluster. To install the kaniko build template, we'll use kubectl to install the kaniko manifest: ```shell kubectl apply -f https://raw.githubusercontent.com/knative/build-templates/master/kaniko/kaniko.yaml ``` ### Register secrets for Docker Hub In order to push the container built from source to Docker Hub, we need to register a secret in Kubernetes for authentication with Docker Hub. There are [detailed instructions](https://github.com/knative/docs/blob/master/build/auth.md#basic-authentication-docker) available, but these are the key steps. Create a new Secret manifest, which we can use to store your Docker Hub credentials. Save this file as `docker-secret.yaml`. ```yaml apiVersion: v1 kind: Secret metadata: name: basic-user-pass annotations: build.knative.dev/docker-0: https://index.docker.io/v1/ type: kubernetes.io/basic-auth data: # Use 'echo -n "username" | base64' to generate this string username: BASE64_ENCODED_USERNAME # Use 'echo -n "password" | base64' to generate this string password: BASE64_ENCODED_PASSWORD ``` On Mac or Linux computers, you can use the following command line to generate the base64 encoded values required for the manifest: ```shell $ echo -n "username" | base64 dXNlcm5hbWU= $ echo -n "password" | base64 cGFzc3dvcmQ= ``` After you have created the manifest file, apply it to your cluster with kubectl: ```shell $ kubectl apply -f docker-secret.yaml secret "basic-user-pass" created ``` ## Deploying the sample Now that you've configured your cluster accordingly, we're ready to deploy the sample service into your cluster. This sample uses `github.com/mchmarny/simple-app` as a basic Go application, but you could replace this GitHub repo with your own. The only requirements are that the repo contain a `Dockerfile` with the instructions for how to build a container for the application. Create a service manifest which defines the service to deploy, including where the source code is and which build-template to use. Create a file named `service.yaml` and copy the following definition. Make sure to replace `{DOCKER_USERNAME}` with your own Docker Hub username. ```yaml apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: app-from-source namespace: default spec: runLatest: configuration: build: source: git: url: https://github.com/mchmarny/simple-app.git revision: master template: name: kaniko arguments: - name: IMAGE value: &image docker.io/{DOCKER_USERNAME}/app-from-source:latest revisionTemplate: spec: container: image: *image imagePullPolicy: Always env: - name: SIMPLE_MSG value: "Hello sample app!" ``` Now you can apply this manifest using kubectl, and watch the results: ```shell # Apply the manifest $ kubectl apply -f service.yaml service "app-from-source" created # Watch the pods for build and serving $ kubectl get pods --watch NAME READY STATUS RESTARTS AGE app-from-source-00001-zhddx 0/1 Init:2/3 0 7s app-from-source-00001-zhddx 0/1 PodInitializing 0 37s app-from-source-00001-zhddx 0/1 Completed 0 38s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Pending 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Pending 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Init:0/1 0 0s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 Init:0/1 0 2s app-from-source-00001-deployment-6d6ff665f9-xfhm5 0/3 PodInitializing 0 3s app-from-source-00001-deployment-6d6ff665f9-xfhm5 2/3 Running 0 6s app-from-source-00001-deployment-6d6ff665f9-xfhm5 3/3 Running 0 11s ``` Once you see the deployment pod switch to the running state, hit Ctrl+C to escape the watch. The build and deployment have finished! To check on the state of the service, get the service object and examine the status block: ```shell $ kubectl get service.serving.knative.dev app-from-source -o yaml [...] status: conditions: - lastTransitionTime: 2018-07-11T20:50:18Z status: "True" type: ConfigurationsReady - lastTransitionTime: 2018-07-11T20:50:56Z status: "True" type: RoutesReady - lastTransitionTime: 2018-07-11T20:50:56Z status: "True" type: Ready domain: app-from-source.default.dibble.cloud latestCreatedRevisionName: app-from-source-00007 latestReadyRevisionName: app-from-source-00007 observedGeneration: 10 traffic: - configurationName: app-from-source percent: 100 revisionName: app-from-source-00007 ``` 1. After the build has completed and the container is pushed to docker hub, you can deploy the app into your cluster. Ensure that the container image value in `service.yaml` matches the container you built in the previous step. Apply the configuration using `kubectl`: ```shell kubectl apply -f service.yaml ``` 1. Now that your service is created, Knative will perform the following steps: * Fetch the revision specified from GitHub and build it into a container * Push the container to Docker Hub * Create a new immutable revision for this version of the app. * Network programming to create a route, ingress, service, and load balance for your app. * Automatically scale your pods up and down (including to zero active pods). 1. To find the IP address for your service, use `kubectl get svc knative-ingressgateway -n istio-system` to get the ingress IP for your cluster. If your cluster is new, it may take sometime for the service to get asssigned an external IP address. ```shell $ kubectl get svc knative-ingressgateway -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE knative-ingressgateway LoadBalancer 10.23.247.74 35.203.155.229 80:32380/TCP,443:32390/TCP,32400:32400/TCP 2d ``` 1. To find the URL for your service, use ```shell $ kubectl get services.serving.knative.dev app-from-source -o=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain NAME DOMAIN app-from-source app-from-source.default.example.com ``` 1. Now you can make a request to your app to see the result. Replace `{IP_ADDRESS}` with the address you see returned in the previous step. ```shell curl -H "Host: app-from-source.default.example.com" http://{IP_ADDRESS} Hello World! ``` ## Removing the sample app deployment To remove the sample app from your cluster, delete the service record: ```shell kubectl delete -f service.yaml ```