Docker is everywhere! Right? I would expect every developer who uses Kubernetes to have the docker CLI installed and configured on their workstation. How could you not?

Well… what if there are some pesky corporate policies that prevent you from pushing to hub.docker.com directly? Crazy? I once worked at a place that blocked Github out of fear of leaking proprietary code to OSS… I asked a colleague who is still there and there is no path to install docker on their workstation. That being said they are exploring using Kubernetes in their datacenter. How’s that going to work?

tl;dr

If you want to push source code to Knative and have it do the heavy lifting of building and pushing a container, here is a script to do so with a single command. Look below for instructions on how to install and run it.

Lets talk about Knative

If you haven’t yet checked out Knative, you should! It has a few elements to know about, for now we care about two of them: build and serving. The build system can do just about anything but for now lets focus on it creating and deploying containers. The serving part is what you would expect, serving containers. So for our goal of deploying a container without the docker CLI on our workstation, this should work.

Lets pull from a Knative example:

Setup Knative with your docker registry credentials Setup the service.yaml to build and deploy a container: Apply and wait!

Sources

Lets look at step 2 a little as its the most interesting:

build:

apiVersion: build.knative.dev/v1alpha1

kind: Build

spec:

serviceAccountName: build-bot

source:

git:

url: https://github.com/mchmarny/simple-app.git

revision: master

Notice that the build configuration has a source. This one is a git repository (e.g., https://github.com/mchmarny/simple-app.git ). If we look at the docs though, we’ll notice Knative can build from a variety of sources. This means we have a few options for getting our source code from our workstation to the Knative build system.

Git as a Source

Git is obviously a great choice. Make a commit, push it, and build a container from the repo. Sounds like a great workflow!

What if we are doing active development and not yet ready for a real commit? Well, we could use a branch and do lots of little “WIP” commits that can be squashed down before being merged. In my experience, some developers will love this workflow, while others will cringe. I’m not here to judge or sway, so instead I’ll just offer a different solution for those cringing.

In fact, that previous place I worked at… they didn’t use git. They used SVN. Normally TortoiseSVN. So if we assume Knative has to have git, then we might exclude some users.

GCS as a Source

Knative can also use buckets for a source. Now I am calling out GCS, but really it can be any bucket system. Notice in the docs it says you can use a custom source. This is because as long as Knative has access to it, it can download the bits.

Lets look at what changing the source to pull from a bucket would look like (and we’ll keep it generic so its easier to imagine pulling from whatever bucket works for you):

build:

apiVersion: build.knative.dev/v1alpha1

kind: Build

spec:

serviceAccountName: build-bot

source:

custom:

image: gcr.io/cloud-builders/gsutil

args: ["rsync", "gs://some-bucket", "."]

So lets break the custom source part down:

image : This is a container image (hosted on gcr.io instead of hub.docker.com ) that has the gsutil CLI. gsutil is used to interact with GCS buckets.

args : This is an array of arguments will be executed by the container. In this case, they will be passed to the gsutil CLI. rsync will copy the contents of the some-bucket bucket to the local directory. This will execute gsutil rsync gs://some-bucket . . This makes the contents available to build a container from.

Cloud Foundry Workflow

Lets now imagine the workflow this presents. It actually starts to resemble the cf push workflow that Cloud Foundry has worked so hard at. If you haven’t had the pleasure of using Cloud Foundry it goes a little something like this:

Write some code that accepts HTTP connections on the port provided by the environment variable PORT . In your terminal, do cf push your-app-name . the cf CLI will then push your directory up and Cloud Foundry will magically (using buildpacks) turn your source code into a container and deploy it.

Its quite simple and many large enterprises are happily deploying their code this way. The barrier to entry is very low. You don’t have to understand docker or containers. Plus, cf is the ONLY CLI you have to have installed and configured.

GCS Workflow

So can we get a cf like workflow using Knative and GCS? Lets think about the steps we would have to take:

Upload source code to a new bucket. Ensure Knative has access to the bucket. Create service.yaml that builds the bucket into a container to be served. Apply and wait!

One thing to note is the previously listed example uses kaniko to build the container. However that means we have to have a Dockerfile . If we’re really wanting to emulate the cf push experience, we should consider using buildpacks. I’ve written about them before if you want more about them. For now, lets stick with kaniko.

Its pretty easy to see those steps and start building a script, so I did that. This script assumes a few things, you have gsutil and kubectl installed and configured.

Install this script:



wget

chmod +x push.sh

sudo mv push.sh /usr/local/bin # Install the push.shwget https://gist.githubusercontent.com/poy/63abaa5c2b710c84dbfb03be440c319e/raw/push.sh -O push.shchmod +x push.shsudo mv push.sh /usr/local/bin

The script wants three things:

Your docker username (configured via the environment variable DOCKER_USERNAME ). The name of the service. Path to the source code.

For example:



git clone

cd simple-app

DOCKER_USERNAME=<your-username> push.sh simple-app . # Deploy a service called simple-appgit clone https://github.com/mchmarny/simple-app.git cd simple-appDOCKER_USERNAME= push.sh simple-app .

You should eventually see in the output the following line:

service.serving.knative.dev/simple-app created

After this, we can follow the instructions in the Knative example on how to wait for our service to be ready and how to curl it.

curl -H "Host: simple-app.default.example.com" {EXTERNAL-IP} <h1>Hello from the sample app!</h1>

Note: If curling this way seems awkward (setting the Host and such), it can be improved. See this post for how to setup a development environment with a custom hostname.

And there you have it! We just deployed a service without ever running or even configuring docker. We didn’t have to make a bunch of “WIP” commits and managed to push an entire service with a single command.

Could this be even better?

So this solution is far from perfect. For one, you have to have gsutil and kubectl configured. You are also still worried about where the container is stored (by setting the DOCKER_USERNAME ) while pushing. If you wanted to push somewhere else (e.g., AWS’ S3 ), then this script would have to be expanded…

I think the next steps are to instead of having a fancy script that emulates the cf push experience, is to instead have a service that is deployed to Knative. The service should be configured to work with various bucket systems, container registries and Knative. It would simply hand the new CLI a signed path to upload the source code to and then deal with Knative directly. This system could also figure out how to deal with buildpacks if a Dockerfile is not available.

By having this service take the configuration ahead of time, the developer wouldn’t have to worry about any of it. It would provide a generic push experience that would allow the source code to easily be pushed to various environments (which was always a goal of Cloud Foundry).