Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Build An Effective Container-Based Local Development Environment

DZone's Guide to

How to Build An Effective Container-Based Local Development Environment

A review of a talk from All Day DevOps in which an expert gives his thoughts on creating dev environments using containers in a DevOps workflow.

· DevOps Zone ·
Free Resource

Learn how integrating security into DevOps to deliver "DevSecOps" requires changing mindsets, processes and technology.

As All Day DevOps 2018 kicked off, one of the day's first sessions was by Dr. Martino Fornasa, DevOps Lead at Kiratech, who explained how to build a local development environment with Kubernetes-based containers.

Let's dive into the key points that he made.

Many developers are already deploying software on containers. But what about local development? Fornasa has tried to get as close as possible to production when developing locally.

Having a good local development workflow is about:

  • Easier onboarding for new developers.
  • Consistent software dependency management.
  • Achieving production parity as much as possible.
  • Running tests locally (faster than having to wait for the CI server).
  • Building knowledge.

But creating a local development environment is hard. Each developer has a different way of working and each technology stack has its own specifics.

For example, when using Docker and Node, you might want to cache the node modules:

So, as you can imagine, working with containers requires some language and technology specific knowledge.

A few years ago, Fornasa rolled out his own solution, as there wasn't much around. He used Docker volume binding to sync his local code directory with the application directory on the container. This worked nice and fast. Fornasa asked the other developers to use the same mechanism.

What could possibly go wrong? Well, a lot. There were speed issues and sync issues, and a lot of garbage was left on the local machine afterward. Also, if developers didn't or couldn't give enough resources to the containers, this didn't work efficiently. So people hated it.

To solve this, Fornasa came up with some implementation goals:

  • Carefully tune for performance and reduce friction.
  • Make it easy for people to do the right thing.
  • Allow them to use their own tools.

When Fornasa built his own tools, he used only Docker. But now, you can run Kubernetes locally, and so we can get the production parity to the next level. We live in exciting times, and the tooling is constantly improving.

But before you begin with local Kubernetes, you should ask yourself if you really want to. Some smaller applications might not reap a lot of benefits. But when your application becomes more complex, containers and Kubernetes will make it easier to set up complex environments (databases, caches, search engines, etc.).

Another benefit is that you can have the same tools for development and deployment. It also enables microservices and allows each dev to run the full system (possibly with external dependencies). Finally, a CI can build the final image and enforce policies.

Fornasa then goes on to explain three approaches.

Auto-Rebuild and Deploy

The first is an approach that can be run on a remote cluster or locally. On each code change, this approach rebuilds the image and deploys it. Fornasa calls this "auto-rebuild and deploy." Skaffold and Draft are tools that come to mind here.

This approach has a higher guarantee of correctness. On the other hand, it can have speed issues because you're rebuilding the entire image.

Draft supports several languages like .NET, Go, Node, PHP, Java, Python, and Ruby. It uses Helm under the hood and can generate your Dockerfile and Helm Chart. According to Fornasa, Draft still misses a system for full automation, like monitoring file changes.

Skaffold, on the other hand, can detect changes and then run a build and deploy. It's basically automatic. Although they have less automatic initialization than Draft, they have great documentation, according to Fornasa. Skaffold also supports the second approach (see below), where it synchronizes the files to the cluster.

Run on Cluster + Synchronize Filesystem

The second approach runs on the cluster and synchronizes the filesystem. This generally works faster, especially for interpreted languages where a complete rebuild is not always necessary.

A downside is that you have a higher chance of drifting from the image built by the CI.

As mentioned, Skaffold can take this approach. Ksync is another tool Fornasa mentioned.

Ksync runs a local service (or daemon) that interacts with the Docker daemon. It syncs files with the container. In the future, Ksync will also be able to execute remote commands. This could be useful if you need to recompile on the container.

Run Locally + Bridge Network

In this third approach, you run your code locally and develop against remote resources. You then bridge the network so that it seems like your code runs in the cluster.

Telepresence is a tool that allows you to run your processes or services locally but still access services in a cloud-based Kubernetes cluster — just like they were running in your local cluster.

With these three interesting approaches, Fornasa concluded his talk on different strategies and tools that can help you build a local development environment when you're working with containers and Kubernetes.

***

Missed Dr. Fornasa's session? Want to watch the rest of All Day DevOps? Simply head over https://www.alldaydevops.com//live and make sure you're registered. You'll receive all of the recordings for free after the conference, and be able to watch the rest of today's sessions.

Learn how enterprises are using tools to automate security in their DevOps toolchain with these DevSecOps Reference Architectures.

Topics:
devops ,all day devops ,development environments ,container configuration

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}