A development workflow for Kubernetes services 
Tags: programming, docker, tutorial, introduction
Published: 2017-11-21 18:46:02

---
title: A development workflow for Kubernetes services 
published: true
description: A basic development workflow for Kubernetes services lets a developer write some code, commit it, and get it running on Kubernetes. It's also important that your development environment be as similar as possible to production, since having two different environments will inevitably introduce bugs. In this tutorial, we'll walk through a basic development workflow that is built around Kubernetes, Docker, and Envoy/Ambassador.
tags: programming, docker, tutorial, introduction
canonical_url: https://www.datawire.io/faster/dev-workflow-intro/
---

A basic development workflow for Kubernetes services lets a developer write some code, commit it, and get it running on Kubernetes. It's also important that your development environment be as similar as possible to production, since having two different environments will inevitably introduce bugs. In this tutorial, we'll walk through a basic development workflow that is built around Kubernetes, Docker, and Envoy/Ambassador.

## Your cloud infrastructure

This tutorial relies on two components in the cloud, Kubernetes and Ambassador. If you haven't already, go ahead and set them up.

* [Kubernetes](https://kubernetes.io)
* [Ambassador](https://www.getambassador.io), a self-service API Gateway for Kubernetes

## 1. A development environment for Kubernetes services

You need a development environment for Kubernetes services. We recommend the following approach:

* A containerized *build/runtime* environment, where your service is always run and built. Containerizing your environment helps insure environmental parity across different development and production environments. It also simplifies the onboarding process for new developers.
* Developing your microservice locally, outside of the cluster. You want a fast code/build/test cycle. If you develop remotely, the additional step of deploying to a Kubernetes cluster introduces significant latency.
* Deploying your service into Kubernetes once you need to share your service with others (e.g., canary testing, internal development, etc.).

You'll need the following tools installed on your laptop:

* git, for source control
* Docker, to build and run your containers
* `kubectl`, to manage your deployment
* [Forge](https://forge.sh), for deploying your service into Kubernetes
* [Telepresence](https://www.telepresence.io), for locally developing your service

Go ahead and install them now, if you haven't already.

## 2. Deploy service to Kubernetes

In a traditional application, the release / operations team manages the deployment of application updates to production. In a microservices architecture, the team is responsible for deploying service updates to production.

We're going to deploy and publish a microservice, from source, into Kubernetes.

1. We've created a simple Python microservice that you can use as a template for your service. This template includes:

   * a `Dockerfile` that specifies how your development environment and runtime environment are configured and built.
   * a `service.yaml` file that customizes deployments for different scenarios (e.g., production, canary, development).
   * a Kubernetes manifest (`k8s/deployment.yaml`) that defines how the service is run in Kubernetes. It also contains the annotations necessary to configure Ambassador for the given service.

   ```
   git clone https://github.com/datawire/hello-world-python
   ```

2. We're going to use Forge to automate and template-ize the deployment process. Run the Forge configuration process:

   ```
   forge setup
   ```

2. The process of getting a service running on a Kubernetes cluster involves a number of steps: building a Docker image, pushing the image to a repository, instantiating a Kubernetes manifest to point to the image, and applying the manifest to the cluster. Forge automates this entire process of deployment:

   ```
   cd hello-world-python
   forge deploy
   ```

3. Now, we're going to test the service. Get the external IP address of Ambassador:

   ```
   kubectl get services ambassador
   NAME         CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
   ambassador   10.11.250.208   35.190.189.139   80:31622/TCP   4d
   ```

4. Access the service via Ambassador:

   ```
   curl 35.190.189.139/hello/
   Hello World (Python)! (up 0:03:13)
   ```

## 3. Live coding

When developing, you want a fast feedback cycle. You'd like to make a code change, and immediately be able to build and test your code. The deployment process we just went through adds latency into the process, since building and deploying a container with your latest changes takes time. Yet, running a service in Kubernetes lets that service access other cloud resources (e.g., other services, databases, etc.).

[Telepresence](https://www.telepresence.io) lets you develop your service locally, while creating a bi-directional proxy to a remote Kubernetes cluster.

1. You'd like for your development environment to be identical to your runtime environment. We're going to do that by using the exact same Dockerfile we use for production to build a development image. Make sure you're in the `hello-world-python` directory, and type:

   ```
   docker build . -t hello-world-dev
   ```


2. Now, we can swap the existing `hello-world` service on Kubernetes for a version of the same service, running in a local container.

  ```
   telepresence --swap-deployment hello-world-stable --docker-run \
    --rm -it -v $(pwd):/service hello-world-dev:latest
   ```

(Note that Forge has automatically appended a `stable` suffix to the deployment name to indicate that the service has been deployed with the `stable` profile specified in the `service.yaml`.) 

3. Telepresence invokes `docker run` to start the container. It also mounts the local filesystem containing the Python source tree into the container. Change the "Hello World" message in `app.py` to a different value:

  ```
   def root(): 
    return "Hello World via Telepresence! (up %s)\n" % elapsed()
   ```  

4. Now, if we test our service via Ambassador, we'll see that we're now routing to the modified version of our service. 

   ```
   curl 35.190.189.139/hello/
   Hello World via Telepresence! (up 0:04:13)
   ```
 

## Want to learn more? 

This article originally appeared on [Datawire](https://www.datawire.io/)'s [Code Faster Guides](https://www.datawire.io/faster/). Check out the other tutorials in this series: 
* [Why your development workflow is so important for microservices](https://www.datawire.io/faster/why-workflow/)
* [Canary deployments, A/B testing, and microservices](https://www.datawire.io/faster/canary-workflow/)
* [Shared development models and multi-service applications](https://www.datawire.io/faster/shared-dev/)

Or try out the open source projects mentioned in this tutorial: 
* [Kubernetes](https://kubernetes.io)
* [Ambassador](https://www.getambassador.io)
* [Forge](https://forge.sh)
* [Telepresence](https://www.telepresence.io/)
* [Docker](https://www.docker.com/)

If you have any questions, reach out to us on [Gitter](https://gitter.im/datawire/home).