Tobias Meyer

Building Confidence on a Docker Devbox

Ruby Unconf 2018

00:00:16.630 Thank you.
00:00:18.680 So, no questions is not the case. You can ask me questions afterwards, and we can discuss them.
00:00:23.090 I said in the presentation at the beginning, welcome! Thank you for showing up to my talk, the first part of the day.
00:00:28.430 First of all, in my job, I think what I'm going to talk about is exciting. I tried to adjust some of the slides to convey the right message. So, it should work.
00:00:36.550 If you have any questions about how we will proceed, please feel free to ask.
00:00:39.690 Also, I would like to know about your experiences with the topic I'm talking about, so I would appreciate it if you could raise your hand.
00:00:48.980 It looks good, so I can keep this part short, I think.
00:01:01.880 So what is this about in general? We are getting more services, more languages, and more diversity in our stacks. There are a lot of different versions of software and many teams working on the same product.
00:01:07.270 Especially in big companies, but also small companies tend to split their systems up and distribute them. However, it's hard, in a setup like this, to run the whole system on your local machine.
00:01:19.320 The problem arises that you don't really have a way to build confidence in what you are holding, especially if you work on infrastructure or back end.
00:01:27.450 When I build it, I want to see it running. Of course, there are tests that should be running, code reviews, and many other things that you should do to build confidence in your code.
00:01:33.349 However, there's nothing like actually seeing it run the way it should and with all of the web services. It's sometimes hard to set up the whole system on your local development machine.
00:01:40.200 So the idea, based on my experience, is to use Docker. Docker and Docker Compose allow you to configure your services to run in containers.
00:01:49.790 These containers have a small operating system. It's not really the whole operating system, as the kernel is reused from the host system, but you have your database or Alpine on top.
00:02:00.090 On top of that, you can install packages or dependencies for your application, and then you can run your application inside this container.
00:02:10.530 Docker Compose allows you to compose these different containers and define how they should be started, what their environment should be, and you can link files into the container.
00:02:20.040 You can even link them together so they can communicate with each other. These services can be the services you build yourself, but also databases, caches, or anything else you might need.
00:02:27.210 The requirements for such a development box should be that it acts like a local staging environment and is usable during development.
00:02:35.640 I want the changes I make to be reflected in this running system as fast as possible. It should be short, easy to bootstrap, and easy to use.
00:02:42.510 We don't want to be bogged down by details while using containers. It should be something you can just pack and play.
00:02:50.830 My experience with a system like this comes from working at Jindo, where we have created a setup using Docker and Docker Compose to run our entire system for quite some time.
00:03:02.600 We have had quite a good experience. We even use it during our continuous integration process to run integration tests.
00:03:11.950 We spin up the whole system during a pull request, run our tests against it, and it automatically shuts down after that.
00:03:21.020 With our new product, Olson & Photos, we are in the process of setting it up as well. The feeling of gaining confidence in the changes we make has greatly improved.
00:03:29.230 Previously, we had a staging environment that was slow because you had to wait for it to deploy and then test it there. If it didn't work, you'd return and deploy again.
00:03:41.060 But with this new setup, you can see what fits a lot better. We want our demos to act like local staging systems, as close to production as possible.
00:03:49.270 To do this, one thing we want to have is a domain name. You shouldn't run your services online by simply exposing ports and giving people access.
00:03:55.480 You need domain names, so the first thing to do is get a domain. This can be done quite easily by using test domains reserved specifically for this use case.
00:04:05.630 Choose a domain with the TLD test. If you want to run this on your local network, you need a nameserver that responds to requests for this domain.
00:04:13.130 You can start a DNS server in your environment to handle requests for the domain. For this example, I'll choose the domain 'devbox.test'.
00:04:23.850 With this setup, you need to make sure your system knows where to ask for the domain name.
00:04:32.330 Unfortunately, many operating systems, like Linux, have to be configured to ask the specific DNS server for those requests.
00:04:42.610 You can bind your web server to this IP address and ensure that your DNS server returns the right IP when queried.
00:04:49.070 With Docker set up on this port, it will always return the same IP address, which is the IP address used for your containers.
00:05:01.230 The first part is done: I can go to my browser and type 'devbox.test', and it should point to the container environment. However, if nothing is running, I won't see any response.
00:05:11.580 This can also be easily solved. There is a nice project by Jay Wilder called NGINX Proxy that acts as a proxy for your containers.
00:05:20.480 It comes with many features, the main one being that you can plug it into your Docker Compose file, and it will parse the configuration for different services.
00:05:29.690 For example, it will look for virtual host and port environment variables and use those to determine under which subdomain a service should be hosted.
00:05:40.230 You bind this proxy to the HTTP and HTTPS port and configure it with the virtual host settings for your services.
00:05:49.670 So when you launch your service, it will automatically become accessible under its appropriate subdomain.
00:05:57.570 Now we are capable of adding services to our Docker Compose setup, and they will all be available under subdomain names.
00:06:07.790 Next, you probably want to enable HTTPS for your services, which is a default requirement in most cases.
00:06:15.270 There are tools available, such as Let's Encrypt, which allow you to generate valid certificates.
00:06:22.200 Alternatively, you can use OpenSSL to generate your own CA and sign a self-signed certificate for your test domain.
00:06:31.200 Once you have this certificate, you can proceed to configure NGINX as a proxy to use these certificates for HTTPS.
00:06:39.420 Unfortunately, for self-signed certificates, you will need to import the public key of your CA into your browser or operating system.
00:06:49.175 Be careful with the privacy of the CA key; if it gets leaked, someone could generate certificates that might compromise your applications.
00:06:57.770 Always keep this key safe, or you can throw it away after generating certificates and create a new CA if needed.
00:07:07.410 Now, we have set up Docker with a DNS that responds to our domain, a proxy that forwards requests to our services, and certificates for HTTPS.
00:07:13.820 The next step is to run all your services inside Docker Compose.
00:07:22.560 This can get messy depending on how your current setup is.
00:07:30.660 Typically, we have the luxury of already running all services on Docker in production.
00:07:39.100 For every service, you need a Docker image as an artifact, and when setting up the dev box, we could theoretically use those images.
00:07:49.740 However, there can be issues with existing Docker images. Sometimes configuration files are baked into the images, or you may have to deal with multiple configurations.
00:08:07.640 For instance, if you are using Webpack, you might have different configurations for different environments.
00:08:16.600 This situation can lead to a lot of work, and there are many strategies for how to handle it, depending on the specifics of your setup.
00:08:26.300 If you have any questions about how a specific service could be imported or the strategies there, please feel free to come talk to me afterwards.
00:08:32.880 Assuming you successfully import all the services you need, you may find that it sounds a bit daunting at first.
00:08:40.170 However, if you start tackling it, you might find it's not so bad.
00:08:47.990 This is especially true for databases, caches, and infrastructure, because there are already images available.
00:08:54.850 Even if you don't find an image for your Ruby service, you can find one based on existing technology.
00:09:01.520 Generally, for most projects, you can just take the code you have and plug it into one of the existing containers.
00:09:05.940 You may need to do some adjustments, but you shouldn't be afraid—it can actually be quite nice.
00:09:14.260 When you have the service running properly in Docker, you won't have to keep reconfiguring your local system repeatedly.
00:09:23.080 Instead, you can just take the Dockerfile and give it to your colleague, who can replicate the same service with the same configuration.
00:09:30.750 Everyone's setup would be identical, eliminating discrepancies.
00:09:38.610 Now that we have a running system with all the necessary services, let's talk about data.
00:09:46.750 If you have pictures or other necessary data for your system, you need to ensure that your database migrations are also run.
00:09:54.300 There are also additional gems or packages that you may want to install.
00:10:00.350 To approach this, you can call the same functions you would on your local machine using commands within Docker.
00:10:06.080 Use the command 'docker-compose run' to execute commands inside a container.
00:10:14.920 I have had successful experiences with executing such commands within the containers.
00:10:22.700 Sometimes, you might need additional configuration, but with some adjustments, it tends to work quite well.
00:10:30.700 However, you may encounter issues—especially concerning SSL communication among services.
00:10:44.150 Sometimes, services are configured to exclusively use SSL for communication, which is a good practice.
00:10:53.470 In such cases, you'll need to provide the necessary development CA certificate to your services.
00:11:03.700 This is straightforward; import the certificate into the CA of your operating system.
00:11:09.830 Simply place the certificate in the certificate store, and it will generate the necessary files.
00:11:18.750 Unfortunately, this process doesn't work seamlessly for all languages.
00:11:26.750 For instance, the security models differ across programming languages, and you'll have to ensure that libraries are configured to use system certificates.
00:11:33.060 Make sure your service can access your local certificate store, so SSL communication can occur securely.
00:11:41.000 Once everything is running, including SSL communication, we should consider mounting our source code into the container.
00:11:48.800 This works well with scripting languages like Ruby, PHP, and Python, and even JavaScript.
00:11:56.520 For compiled languages like Go or Java, you might want to compile artifacts and run them.
00:12:02.450 However, you may be pleased to know that there are tools available that can detect changes and rebuild containers.
00:12:11.800 On a development machine, you can mount your source code into the Docker container.
00:12:20.000 You might also want to bind your project's directory to reduce the need for repeated installations.
00:12:27.050 If you adjust configurations like environment variables or system settings, you can do so through your Docker Compose file.
00:12:34.850 Furthermore, Docker Compose supports inheritance, allowing for multiple Compose files to be combined.
00:12:44.670 In the first file, you define the standard setup, and then in a second file, you add specific development configurations.
00:12:51.970 By using this feature, you can create a setup tailored for the specific service you're developing.
00:12:59.990 You can also ensure that any changes trigger relevant file system events forwarded to the container.
00:13:05.480 Be aware that if you're using Docker Machine, you may experience challenges with NFS mounting.
00:13:13.150 On the other hand, if you're running directly on Linux, those issues will likely be resolved.
00:13:20.870 Another feature of Docker Compose that can enhance your configuration is the use of placeholders, allowing for greater flexibility in environment variables.
00:13:32.100 For instance, you can define a DNS server configuration and reuse it across your setup. It makes managing configurations easier.
00:13:43.430 However, one thing I find missing is the ability to define included files in your configuration, which would simplify management.
00:13:51.150 A big Docker Compose file with all your services can quickly become unwieldy.
00:14:00.140 It’s preferable to have each service defined in different configuration files for better organization.
00:14:08.529 Additionally, it's important to keep up with the latest updates on how project names are being handled in Docker Compose.
00:14:16.170 This includes making sure that your project names are correctly stripped of dashes, which may not happen in new versions.
00:14:25.530 To ensure consistency, it's a good practice to define the project name in an environment variable.
00:14:30.980 As a side note, make sure that the docker version and network settings are aligned throughout your environment.
00:14:44.430 It is also advisable to create some toolset to help with setup, execution, and maintaining your local environment.
00:14:53.080 This includes placing DNS files in appropriate locations and managing migrations.
00:14:59.700 It's crucial to ensure that everyone is using the same tooling and that they are familiar with it.
00:15:06.800 That’s it from my side, and here are some links for the libraries I used and my contact information.
00:15:14.140 If you have questions or if you're interested in Docker, server management, or Raspberry Pi, feel free to reach out.
00:15:18.280 Thank you very much!
00:15:26.960 One thing I like to do during retrospectives is to ask for feedback.
00:15:30.200 I would like you to rate your time investment on a scale from one to five.
00:15:34.380 One finger means it was a very poor time investment, while five fingers indicate the best time investment.