Learn Docker – Fundamentals of Docker 19.x - Gabriel N. Schenker - E-Book

Learn Docker – Fundamentals of Docker 19.x E-Book

Gabriel N. Schenker

0,0
36,59 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Explore the core functionality of containerizing your applications and making them production-ready




Key Features



  • Grasp basic to advanced Docker concepts with this comprehensive guide


  • Get acquainted with Docker containers, Docker images, orchestrators, cloud integration, and networking


  • Learn to simplify dependencies and deploy and test containers in production



Book Description



Containers enable you to package an application with all the components it needs, such as libraries and other dependencies, and ship it as one package. Docker containers have revolutionized the software supply chain in both small and large enterprises.






Starting with an introduction to Docker fundamentals and setting up an environment to work with it, you'll delve into concepts such as Docker containers, Docker images, and Docker Compose. As you progress, the book will help you explore deployment, orchestration, networking, and security. Finally, you'll get to grips with Docker functionalities on public clouds such as Amazon Web Services (AWS), Azure, and Google Cloud Platform (GCP), and learn about Docker Enterprise Edition features. Additionally, you'll also discover the benefits of increased security with the use of containers.






By the end of this Docker book, you'll be able to build, ship, and run a containerized, highly distributed application on Docker Swarm or Kubernetes, running on-premises or in the cloud.




What you will learn



  • Containerize your traditional or microservice-based applications


  • Develop, modify, debug, and test an application running inside a container


  • Share or ship your application as an immutable container image


  • Build a Docker Swarm and a Kubernetes cluster in the cloud


  • Run a highly distributed application using Docker Swarm or Kubernetes


  • Update or rollback a distributed application with zero downtime


  • Secure your applications with encapsulation, networks, and secrets


  • Troubleshoot a containerized, highly distributed application in the cloud



Who this book is for



This book is for Linux professionals, system administrators, operations engineers, DevOps engineers, and developers or stakeholders who are interested in getting started with Docker from scratch. No prior experience with Docker containers is required. Users with a Linux system would be able to take full advantage of this book.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB

Seitenzahl: 650

Veröffentlichungsjahr: 2020

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Learn Docker – Fundamentals of Docker 19.xSecond Edition

 

 

 

Build, test, ship, and run containers with Docker and Kubernetes

 

 

 

 

 

 

 

 

Gabriel N. Schenker

 

 

 

 

 

 

 

 

 

 

 

 

 

BIRMINGHAM - MUMBAI

Learn Docker – Fundamentals of Docker 19.x Second Edition

Copyright © 2020 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

 

Commissioning Editor: Vijin BorichaAcquisition Editor: Shrilekha InaniContent Development Editor: Ronn KurienSenior Editor: Richard Brookes-BlandTechnical Editor: Sarvesh JaywantCopy Editor: Safis EditingProject Coordinator: Neil DmelloProofreader: Safis EditingIndexer: Tejal Daruwale SoniProduction Designer: Deepika Naik

First published: April 2018 Second edition: March 2020

Production reference: 1130320

Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

ISBN 978-1-83882-747-2

www.packt.com

 

Packt.com

Subscribe to our online digital library for full access to over 7,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.

Why subscribe?

Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals

Improve your learning with Skill Plans built especially for you

Get a free eBook or video every month

Fully searchable for easy access to vital information

Copy and paste, print, and bookmark content

Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.

At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks. 

Contributors

About the author

Gabriel N. Schenker has more than 25 years of experience as an independent consultant, architect, leader, trainer, mentor, and developer. Currently, Gabriel works as Lead Solution Architect at Techgroup Switzerland. Prior to that, Gabriel worked as Lead Curriculum Developer at Docker and at Confluent. Gabriel has a Ph.D. in Physics, and he is a Docker Captain, a Certified Docker Associate, a Certified Kafka Developer and Operator, and an ASP Insider. When not working, Gabriel enjoys time with his wonderful wife Veronicah and his children.

I want to give special thanks to my editors, Ronn Kurien and Suzanne Coutinho, who patiently helped me to get this book done and get it done right.

About the reviewer

Francisco Javier Ramírez Urea is a technology enthusiast and professional, Docker Captain, casual developer, open source advocate, a certified trainer and solutions architect at HoplaSoftware, and a technical book writer and reviewer.

He is also a Kubernetes Certified Administrator, a Docker Certified Associate, a Docker Certified Instructor, and a Docker MTA program Consultant, as well as a Docker/Kubernetes and NGINX expert and a DevOps/CI-CD solutions integrator.

He currently works as a solutions architect focused on containers and microservices technologies. He is passionate to teach his students everything he know. Continuous learning is the main motivation of his career.

Packt is searching for authors like you

If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.

Table of Contents

Title Page

Copyright and Credits

Learn Docker – Fundamentals of Docker 19.x Second Edition

About Packt

Why subscribe?

Contributors

About the author

About the reviewer

Packt is searching for authors like you

Preface

Who this book is for

What this book covers

To get the most out of this book

Download the example code files

Download the color images

Conventions used

Get in touch

Reviews

Section 1: Motivation and Getting Started

What Are Containers and Why Should I Use Them?

What are containers?

Why are containers important?

What's the benefit for me or for my company?

The Moby project

Docker products

Docker CE

Docker EE

Container architecture

Summary

Questions

Further reading

Setting Up a Working Environment

Technical requirements

The Linux command shell

PowerShell for Windows

Using a package manager

Installing Homebrew on macOS

Installing Chocolatey on Windows

Installing Git

Choosing a code editor

Installing VS Code on macOS

Installing VS Code on Windows

Installing VS Code on Linux

Installing VS Code extensions

Installing Docker for Desktop

Installing Docker for Desktop on macOS

Installing Docker for Desktop on Windows

Installing Docker CE on Linux

Installing Docker Toolbox

Installing Docker Toolbox on macOS

Installing Docker Toolbox on Windows

Setting up Docker Toolbox

Installing Minikube

Installing Minikube on macOS and Windows

Testing Minikube and kubectl

Summary

Questions

Further reading

Section 2: Containerization, from Beginner to Black Belt

Mastering Containers

Technical requirements

Running the first container

Starting, stopping, and removing containers

Running a random trivia question container

Listing containers

Stopping and starting containers

Removing containers

Inspecting containers

Exec into a running container

Attaching to a running container

Retrieving container logs

Logging drivers

Using a container-specific logging driver

Advanced topic – changing the default logging driver

Anatomy of containers

Architecture

Namespaces

Control groups (cgroups)

Union filesystem (Unionfs)

Container plumbing

runC

Containerd

Summary

Questions

Further reading

Creating and Managing Container Images

What are images?

The layered filesystem

The writable container layer

Copy-on-write

Graph drivers

Creating images

Interactive image creation

Using Dockerfiles

The FROM keyword

The RUN keyword

The COPY and ADD keywords

The WORKDIR keyword

The CMD and ENTRYPOINT keywords

A complex Dockerfile

Building an image

Multi-step builds

Dockerfile best practices

Saving and loading images

Lift and shift: Containerizing a legacy app

Analysis of external dependencies

Source code and build instructions

Configuration

Secrets

Authoring the Dockerfile

The base image

Assembling the sources

Building the application

Defining the start command

Why bother?

Sharing or shipping images

Tagging an image

Image namespaces

Official images

Pushing images to a registry

Summary

Questions

Further reading

Data Volumes and Configuration

Technical requirements

Creating and mounting data volumes

Modifying the container layer

Creating volumes

Mounting a volume

Removing volumes

Accessing volumes created with Docker for Desktop

Sharing data between containers

Using host volumes

Defining volumes in images

Configuring containers

Defining environment variables for containers

Using configuration files

Defining environment variables in container images

Environment variables at build time

Summary

Questions

Further reading

Debugging Code Running in Containers

Technical requirements

Evolving and testing code running in a container

Mounting evolving code into the running container

Auto restarting code upon changes

Auto-restarting for Node.js

Auto-restarting for Python

Auto-restarting for .NET

Line-by-line code debugging inside a container

Debugging a Node.js application

Debugging a .NET application

Instrumenting your code to produce meaningful logging information

Instrumenting a Python application

Instrumenting a .NET C# application

Using Jaeger to monitor and troubleshoot

Summary

Questions

Further reading

Using Docker to Supercharge Automation

Technical requirements

Executing simple admin tasks in a container

Using test containers

Integration tests for a Node.js application

The Testcontainers project

Using Docker to power a CI/CD pipeline

Summary

Questions

Further reading

Advanced Docker Usage Scenarios

Technical requirements

All of the tips and tricks of a Docker pro

Keeping your Docker environment clean

Running Docker in Docker

Formatting the output of common Docker commands

Filtering the output of common Docker commands

Optimizing your build process

Limiting resources consumed by a container

Read-only filesystem

Avoid running a containerized app as root 

Running your Terminal in a remote container and accessing it via HTTPS

Running your development environment inside a container

Running your code editor in a remote container and accessing it via HTTPS

Summary

Questions

Further reading

Section 3: Orchestration Fundamentals and Docker Swarm

Distributed Application Architecture

Understanding the distributed application architecture

Defining the terminology

Patterns and best practices

Loosely coupled components

Stateful versus stateless

Service discovery

Routing

Load balancing

Defensive programming

Retries

Logging

Error handling

Redundancy

Health checks

Circuit breaker pattern

Running in production

Logging

Tracing

Monitoring

Application updates

Rolling updates

Blue-green deployments

Canary releases

Irreversible data changes

Rollback

Summary

Questions

Further reading

Single-Host Networking

Technical requirements

Dissecting the container network model

Network firewalling

Working with the bridge network

The host and null network

The host network

The null network

Running in an existing network namespace

Managing container ports

HTTP-level routing using a reverse proxy

Containerizing the monolith

Extracting the first microservice

Using Traefik to reroute traffic

Summary

Questions

Further reading

Docker Compose

Technical requirements

Demystifying declarative versus imperative

Running a multi-service app

Building images with Docker Compose

Running an application with Docker Compose

Scaling a service

Building and pushing an application

Using Docker Compose overrides

Summary

Questions

Further reading

Orchestrators

What are orchestrators and why do we need them?

The tasks of an orchestrator

Reconciling the desired state

Replicated and global services

Service discovery

Routing

Load balancing

Scaling

Self-healing

Zero downtime deployments

Affinity and location awareness

Security

Secure communication and cryptographic node identity

Secure networks and network policies

Role-based access control (RBAC)

Secrets

Content trust

Reverse uptime

Introspection

Overview of popular orchestrators

Kubernetes

Docker Swarm

Apache Mesos and Marathon

Amazon ECS

Microsoft ACS 

Summary

Questions

Further reading

Introduction to Docker Swarm

The Docker Swarm architecture

Swarm nodes

Swarm managers

Swarm workers

Stacks, services, and tasks

Services

Task

Stack

Multi-host networking

Creating a Docker Swarm

Creating a local single node swarm

Creating a local Swarm in VirtualBox or Hyper-V

Using Play with Docker to generate a Swarm

Creating a Docker Swarm in the cloud

Deploying a first application

Creating a service

Inspecting the service and its tasks

Logs of a service

Reconciling the desired state

Deleting a service or a stack

Deploying a multi-service stack

The swarm routing mesh

Summary

Questions

Further reading

Zero-Downtime Deployments and Secrets

Technical requirements

Zero-downtime deployment

Popular deployment strategies

Rolling updates

Health checks

Rollback

Blue–green deployments

Canary releases

Storing configuration data in the swarm

Protecting sensitive data with Docker secrets

Creating secrets

Using a secret

Simulating secrets in a development environment

Secrets and legacy applications

Updating secrets

Summary

Questions

Further reading

Section 4: Docker, Kubernetes, and the Cloud

Introduction to Kubernetes

Technical requirements

Kubernetes architecture

Kubernetes master nodes

Cluster nodes

Introduction to Minikube

Kubernetes support in Docker for Desktop

Introduction to pods

Comparing Docker container and Kubernetes pod networking

Sharing the network namespace

Pod life cycle

Pod specifications

Pods and volumes

Kubernetes ReplicaSet

ReplicaSet specification

Self-healing

Kubernetes deployment

Kubernetes service

Context-based routing

Comparing SwarmKit with Kubernetes

Summary

Questions

Further reading

Deploying, Updating, and Securing an Application with Kubernetes

Technical requirements

Deploying a first application

Deploying the web component

Deploying the database

Streamlining the deployment

Defining liveness and readiness

Kubernetes liveness probe

Kubernetes readiness probe

Kubernetes startup probe

Zero downtime deployments

Rolling updates

Blue-green deployment

Kubernetes secrets

Manually defining secrets

Creating secrets with kubectl

Using secrets in a pod

Secret values in environment variables

Summary

Questions

Further reading

Monitoring and Troubleshooting an App Running in Production

Technical requirements

Monitoring an individual service

Instrumenting a Node.js-based service

Instrumenting a .NET Core-based service

Using Prometheus to monitor a distributed application

Architecture

Deploying Prometheus to Kubernetes

Deploying our application services to Kubernetes

Deploying Grafana to Kubernetes

Troubleshooting a service running in production

The netshoot container

Summary

Questions

Further reading

Running a Containerized App in the Cloud

Technical requirements

Deploying and using Docker EE on AWS

Provisioning the infrastructure

Installing Docker

Installing Docker UCP

Using remote admin for the UCP cluster

Deploying to Docker Swarm

Deploying to Kubernetes

Exploring Microsoft's Azure Kubernetes Service (AKS)

Preparing the Azure CLI

Creating a container registry on Azure

Pushing our images to ACR

Creating a Kubernetes cluster

Deploying our application to the Kubernetes cluster

Understanding GKE

Summary

Questions

Further reading

Assessments

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7 

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Chapter 16

Chapter 17

Chapter 18

Other Books You May Enjoy

Leave a review - let other readers know what you think

Preface

Developers are faced with ever-increasing pressure to build, modify, test, and deploy highly distributed applications in a high cadence. Operations engineers are looking for a uniform deployment strategy that encompasses most or all of their ever-growing portfolio of applications, and stakeholders want to keep their total cost of ownership low. Docker containers combined with a container orchestrator such as Kubernetes help them all to achieve these goals.

Docker containers accelerate and simplify the building, shipping, and running of highly distributed applications. Containers turbo-charge CI/CD pipelines, and containerized applications allow a company to standardize on one common deployment platform, such as Kubernetes. Containerized applications are more secure and can be run on any platform that's able to run containers, on premises or in the cloud.

Who this book is for

This book is targeted at system administrators, operations engineers, DevOps engineers, and developers or stakeholders who are interested in getting started with Docker from scratch.

What this book covers

Chapter 1, What Are Containers and Why Should I Use Them?, introduces the concept of containers and why they are so extremely useful in the software industry.

Chapter 2, Setting Up a Working Environment, discusses in detail how to set up an ideal environment for developers, DevOps, and operators that can be used when working with Docker containers.

Chapter 3, Mastering Containers, explains how to start, stop, and remove containers. We will also see how to inspect containers to retrieve additional metadata from them. Furthermore, we'll see how to run additional processes, how to attach to the main process in an already running container, and how to retrieve logging information from a container that is produced by the processes running inside it. Finally, the chapter introduces the inner workings of a container, including such things as Linux namespaces and groups.

Chapter 4, Creating and Managing Container Images, presents the different ways to create the container images that serve as the templates for containers. It introduces the inner structure of an image and how it is built. This chapter also explains how to lift and shift an existing legacy application so that it can run in containers.

Chapter 5, Data Volumes and Configuration, introduces data volumes, which can be used by stateful components running in containers. The chapter also shows how we can define individual environment variables for the application running inside the container, as well as how to use files containing whole sets of configuration settings.

Chapter 6, Debugging Code Running in Containers, discusses techniques commonly used to allow a developer to evolve, modify, debug, and test their code while running in a container. With these techniques at hand, the developer will enjoy a frictionless development process for applications running in a container, similar to what they experience when developing applications that run natively.

Chapter 7, Using Docker to Supercharge Automation, shows how we can use tools to perform administrative tasks without having to install those tools on the host computer. We will also see how to use containers that host and run test scripts or code used to test and validate application services running in containers. Finally, this chapter guides us through the task of building a simple Docker-based CI/CD pipeline.

Chapter 8, Advanced Docker Usage Scenarios, presents advanced tips, tricks, and concepts that are useful when containerizing complex distributed applications, or when using Docker to automate sophisticated tasks.

Chapter 9, Distributed Application Architecture, introduces the concept of a distributed application architecture and discusses the various patterns and best practices that are required to run a distributed application successfully. Finally, it discusses the additional requirements that need to be fulfilled to run such an application in production.

Chapter 10, Single-Host Networking, presents the Docker container networking model and its single-host implementation in the form of the bridge network. This chapter introduces the concept of software-defined networks and explains how they are used to secure containerized applications. It also discusses how container ports can be opened to the public and thus make containerized components accessible from the outside world. Finally, it introduces Traefik, a reverse proxy, to enable sophisticated HTTP application-level routing between containers.

Chapter 11, Docker Compose, addresses the concept of an application consisting of multiple services, each running in a container, and how Docker Compose allows us to easily build, run, and scale such an application using a declarative approach.

Chapter 12, Orchestrators, presents the concept of orchestrators. It explains why orchestrators are needed and how they work conceptually. The chapter will also provide an overview of the most popular orchestrators and name a few of their pros and cons.

Chapter 13, Introduction to Docker Swarm, introduces Docker's native orchestrator, SwarmKit. We will see all the concepts and objects SwarmKit uses to deploy and run a distributed, resilient, robust, and highly available application in a cluster on premises or in the cloud. The chapter also introduces how SwarmKit ensures secure applications using software-defined networks to isolate containers and secrets to protect sensitive information. Additionally, this chapter shows how to install a highly available Docker swarm in the cloud. It introduces the routing mesh, which provides Layer 4 routing and load balancing. Finally, it shows how to deploy an application consisting of multiple services onto the swarm.

Chapter 14,  Zero-Downtime Deployments and Secrets, explains how to deploy services or applications onto a Docker swarm with zero downtime and automatic rollback capabilities. It also introduces secrets as a means to protect sensitive information.

Chapter 15, Introduction to Kubernetes, introduces the current most popular container orchestrator. It introduces the core Kubernetes objects that are used to define and run a distributed, resilient, robust, and highly available application in a cluster. Finally, it introduces MiniKube as a way to locally deploy a Kubernetes application, and also the integration of Kubernetes with Docker for Mac and Docker for Windows.

Chapter 16, Deploying, Updating, and Securing an Application with Kubernetes, explains how to deploy, update, and scale applications into a Kubernetes cluster. It also explains how to instrument your application services with liveness and readiness probes to support Kubernetes in its health and availability checking. Furthermore, the chapter explains how zero-downtime deployments are achieved to enable disruption-free updates and rollbacks of mission-critical applications. Finally, the chapter introduces Kubernetes secrets as a means to configure services and protect sensitive data.

Chapter 17, Monitoring and Troubleshooting an App Running in Production, teaches different techniques to monitor an individual service or a whole distributed application running on a Kubernetes cluster. It also shows how to troubleshoot an application service that is running in production without altering the cluster or the cluster nodes on which the service is running.

Chapter 18, Running a Containerized App in the Cloud, provides an overview of some of the most popular ways of running containerized applications in the cloud. We include self-hosting and hosted solutions and discuss their pros and cons. Fully managed offerings of vendors such as Microsoft Azure and Google Cloud Engine are briefly discussed.

To get the most out of this book

A solid understanding of distributed application architecture and an interest in accelerating and simplifying the building, shipping, and running of highly distributed applications are expected. No prior experience with Docker containers is required.

Access to a computer with Windows 10 Professional or macOS installed is highly recommended. The computer should have at least 16 GB of memory.

Software/Hardware covered in the book

OS Requirements

Docker for Desktop, Docker Toolbox, Visual Studio Code, Powershell or Bash Terminal.

Windows 10 Pro/macOS/ Linux minimum of 8GB RAM

 

If you are using the digital version of this book, we advise you to type the code yourself or access the code via the GitHub repository (link available in the next section). Doing so will help you avoid any potential errors related to copy/pasting of code.

Download the example code files

You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.

You can download the code files by following these steps:

Log in or register at

 

www.packt.com

.

Select the

 

Support

 

tab.

Click on

 

Code Downloads

.

Enter the name of the book in the

 

Search

 

box and follow the onscreen instructions.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

WinRAR/7-Zip for Windows

Zipeg/iZip/UnRarX for Mac

7-Zip/PeaZip for Linux

The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Learn-Docker---Fundamentals-of-Docker-19.x-Second-Edition. In case there's an update to the code, it will be updated on the existing GitHub repository.

We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

Download the color images

We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: http://www.packtpub.com/sites/default/files/downloads/9781838827472_ColorImages.pdf.

Conventions used

There are a number of text conventions used throughout this book.

CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "The container runtime on a Docker host consists of containerd and runc."

A block of code is set as follows:

{ "name": "api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC"}

When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:

ARG BASE_IMAGE_VERSION=12.7-stretch

FROM node:

${BASE_IMAGE_VERSION}

WORKDIR /appCOPY packages.json .RUN npm installCOPY . .CMD npm start

Any command-line input or output is written as follows:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Select System info from the Administration panel."

Warnings or important notes appear like this.
Tips and tricks appear like this.

Get in touch

Feedback from our readers is always welcome.

General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].

Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.

Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.

If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

Reviews

Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!

For more information about Packt, please visit packt.com.

Section 1: Motivation and Getting Started

The objective of Part One is to introduce you to the concept of containers and explain why they are so extremely useful in the software industry. You will also prepare your working environment for the use of Docker.

This section comprises the following chapters:

Chapter 1

,

What Are Containers and Why Should I Use Them?

Chapter 2

,

Setting Up a Working Environment

What Are Containers and Why Should I Use Them?

This first chapter will introduce you to the world of containers and their orchestration. This book starts from the very beginning, in that it assumes that you have no prior knowledge of containers, and will give you a very practical introduction to the topic.

In this chapter, we will focus on the software supply chain and the friction within it. Then, we'll present containers, which are used to reduce this friction and add enterprise-grade security on top of it. We'll also look into how containers and the ecosystem around them are assembled. We'll specifically point out the distinction between the upstream Open Source Software (OSS) components, united under the code name Moby, that form the building blocks of the downstream products of Docker and other vendors.

The chapter covers the following topics:

What are containers?

Why are containers important?

What's the benefit for me or for my company?

The Moby project

Docker products

Container architecture

After completing this module, you will be able to do the following:

Explain what containers are, using an analogy such as physical containers, in a few simple sentences to an interested layman

Justify why containers are so important using an analogy such as physical containers versus traditional shipping or apartment homes versus single-family homes, and so on, to an interested lay person

Name at least four upstream open source components that are used by Docker products, such as Docker for Desktop

Identify at least three Docker products

What are containers?

A software container is a pretty abstract thing, so it might help if we start with an analogy that should be pretty familiar to most of you. The analogy is a shipping container in the transportation industry. Throughout history, people have been transporting goods from one location to another by various means. Before the invention of the wheel, goods would most probably have been transported in bags, baskets, or chests on the shoulders of the humans themselves, or they might have used animals such as donkeys, camels, or elephants to transport them.

With the invention of the wheel, transportation became a bit more efficient as humans built roads that they could move their carts along. Many more goods could be transported at a time. When the first steam-driven machines, and later gasoline-driven engines, were introduced, transportation became even more powerful. We now transport huge amounts of goods on trains, ships, and trucks. At the same time, the types of goods became more and more diverse, and sometimes complex to handle.

In all these thousands of years, one thing didn't change, and that was the necessity to unload goods at a target location and maybe load them onto another means of transportation. Take, for example, a farmer bringing a cart full of apples to a central train station where the apples are then loaded onto a train, together with all the apples from many other farmers. Or think of a winemaker bringing his barrels of wine with a truck to the port where they are unloaded, and then transferred to a ship that will transport them overseas.

This unloading from one means of transportation and loading onto another means of transportation was a really complex and tedious process. Every type of product was packaged in its own way and thus had to be handled in its own particular way. Also, loose goods faced the risk of being stolen by unethical workers or damaged in the process of being handled.

Then, there came containers and they totally revolutionized the transportation industry. A container is just a metallic box with standardized dimensions. The length, width, and height of each container is the same. This is a very important point. Without the World agreeing on a standard size, the whole container thing would not have been as successful as it is now.

Now, with standardized containers, companies who want to have their goods transported from A to B package those goods into these containers. Then, they call a shipper, which comes with a standardized means for transportation. This can be a truck that can load a container or a train whose wagons can each transport one or several containers. Finally, we have ships that are specialized in transporting huge numbers of containers. Shippers never need to unpack and repackage goods. For a shipper, a container is just a black box, and they are not interested in what is in it, nor should they care in most cases. It is just a big iron box with standard dimensions. Packaging goods into containers is now fully delegated to the parties who want to have their goods shipped, and they should know how to handle and package those goods.

Since all containers have the same agreed-upon shape and dimensions, shippers can use standardized tools to handle containers; that is, cranes that unload containers, say from a train or a truck, and load them onto a ship and vice versa. One type of crane is enough to handle all the containers that come along over time. Also, the means of transportation can be standardized, such as container ships, trucks, and trains.

Because of all this standardization, all the processes in and around shipping goods could also be standardized and thus made much more efficient than they were before the age of containers.

Now, you should have a good understanding of why shipping containers are so important and why they revolutionized the whole transportation industry. I chose this analogy purposefully, since the software containers that we are going to introduce here fulfill the exact same role in the so-called software supply chain that shipping containers do in the supply chain of physical goods.

In the old days, developers would develop a new application. Once that application was completed in their eyes, they would hand that application over to the operations engineers, who were then supposed to install it on the production servers and get it running. If the operations engineers were lucky, they even got a somewhat accurate document with installation instructions from the developers. So far, so good, and life was easy.

But things get a bit out of hand when, in an enterprise, there are many teams of developers that create quite different types of application, yet all of them need to be installed on the same production servers and kept running there. Usually, each application has some external dependencies, such as which framework it was built on, what libraries it uses, and so on. Sometimes, two applications use the same framework but in different versions that might or might not be compatible with each other. Our operations engineer's life became much harder over time. They had to be really creative with how they could load their ship, (their servers,) with different applications without breaking something.

Installing a new version of a certain application was now a complex project on its own, and often needed months of planning and testing. In other words, there was a lot of friction in the software supply chain. But these days, companies rely more and more on software, and the release cycles need to become shorter and shorter. We cannot afford to just release twice a year or so anymore. Applications need to be updated in a matter of weeks or days, or sometimes even multiple times per day. Companies that do not comply risk going out of business, due to the lack of agility. So, what's the solution?

One of the first approaches was to use virtual machines (VMs). Instead of running multiple applications, all on the same server, companies would package and run a single application on each VM. With this, all the compatibility problems were gone and life seemed to be good again. Unfortunately, that happiness didn't last long. VMs are pretty heavy beasts on their own since they all contain a full-blown operating system such as Linux or Windows Server, and all that for just a single application. This is just as if you were in the transportation industry and were using a whole ship just to transport a single truckload of bananas. What a waste! That could never be profitable.

The ultimate solution to this problem was to provide something that is much more lightweight than VMs, but is also able to perfectly encapsulate the goods it needs to transport. Here, the goods are the actual application that has been written by our developers, plus – and this is important – all the external dependencies of the application, such as its framework, libraries, configurations, and more. This holy grail of a software packaging mechanism was the Docker container.

Developers use Docker containers to package their applications, frameworks, and libraries into them, and then they ship those containers to the testers or  operations engineers. To testers and operations engineers, a container is just a black box. It is a standardized black box, though. All containers, no matter what application runs inside them, can be treated equally. The engineers know that, if any container runs on their servers, then any other containers should run too. And this is actually true, apart from some edge cases, which always exist.

Thus, Docker containers are a means to package applications and their dependencies in a standardized way. Docker then coined the phrase Build, ship, and run anywhere.

Why are containers important?

These days, the time between new releases of an application become shorter and shorter, yet the software itself doesn't become any simpler. On the contrary, software projects increase in complexity. Thus, we need a way to tame the beast and simplify the software supply chain.

Also, every day, we hear that cyber-attacks are on the rise. Many well-known companies are and have been affected by security breaches. Highly sensitive customer data gets stolen during such events, such as social security numbers, credit card information, and more. But not only customer data is compromised – sensitive company secrets are stolen too.

Containers can help in many ways. First of all, Gartner found that applications running in a container are more secure than their counterparts not running in a container. Containers use Linux security primitives such as Linux kernel namespaces to sandbox different applications running on the same computers and control groups (cgroups) in order to avoid the noisy-neighbor problem, where one bad application is using all the available resources of a server and starving all other applications.

Due to the fact that container images are immutable, it is easy to have them scanned for common vulnerabilities and exposures (CVEs), and in doing so, increase the overall security of our applications.

Another way to make our software supply chain more secure is to have our containers use a content trust. A content trust basically ensures that the author of a container image is who they pretend to be and that the consumer of the container image has a guarantee that the image has not been tampered with in transit. The latter is known as a man-in-the-middle (MITM) attack.

Everything I have just said is, of course, technically also possible without using containers, but since containers introduce a globally accepted standard, they make it so much easier to implement these best practices and enforce them.

OK, but security is not the only reason why containers are important. There are other reasons too.

One is the fact that containers make it easy to simulate a production-like environment, even on a developer's laptop. If we can containerize any application, then we can also containerize, say, a database such as Oracle or MS SQL Server. Now, everyone who has ever had to install an Oracle database on a computer knows that this is not the easiest thing to do, and it takes up a lot of precious space on your computer. You wouldn't want to do that to your development laptop just to test whether the application you developed really works end-to-end. With containers at hand, we can run a full-blown relational database in a container as easily as saying 1, 2, 3. And when we're done with testing, we can just stop and delete the container and the database will be gone, without leaving a trace on our computer.

Since containers are very lean compared to VMs, it is not uncommon to have many containers running at the same time on a developer's laptop without overwhelming the laptop.

A third reason why containers are important is that operators can finally concentrate on what they are really good at: provisioning the infrastructure and running and monitoring applications in production. When the applications they have to run on a production system are all containerized, then operators can start to standardize their infrastructure. Every server becomes just another Docker host. No special libraries or frameworks need to be installed on those servers, just an OS and a container runtime such as Docker.

Also, operators do not have to have intimate knowledge of the internals of applications anymore, since those applications run self-contained in containers that ought to look like black boxes to them, similar to how shipping containers look to the personnel in the transportation industry.

What's the benefit for me or for my company?

Somebody once said that, today, every company of a certain size has to acknowledge that they need to be a software company. In this sense, a modern bank is a software company that happens to specialize in the business of finance. Software runs all businesses, period. As every company becomes a software company, there is a need to establish a software supply chain. For the company to remain competitive, their software supply chain has to be secure and efficient. Efficiency can be achieved through thorough automation and standardization. But in all three areas – security, automation, and standardization – containers have been shown to shine. Large and well-known enterprises have reported that, when containerizing existing legacy applications (many call them traditional applications) and establishing a fully automated software supply chain based on containers, they can reduce the cost for the maintenance of those mission-critical applications by a factor of 50% to 60% and they can reduce the time between new releases of these traditional applications by up to 90%.

That being said, the adoption of container technologies saves these companies a lot of money, and at the same time it speeds up the development process and reduces the time to market.

The Moby project

Originally, when Docker (the company) introduced Docker containers, everything was open source. Docker didn't have any commercial products at this time. The Docker engine that the company developed was a monolithic piece of software. It contained many logical parts, such as the container runtime, a network library, a RESTful (REST) API, a command-line interface, and much more.

Other vendors or projects such as Red Hat or Kubernetes were using the Docker engine in their own products, but most of the time, they were only using part of its functionality. For example, Kubernetes did not use the Docker network library for the Docker engine but provided its own way of networking. Red Hat, in turn, did not update the Docker engine frequently and preferred to apply unofficial patches to older versions of the Docker engine, yet they still called it the Docker engine.

Out of all these reasons, and many more, the idea emerged that Docker had to do something to clearly separate the Docker open source part from the Docker commercial part. Furthermore, the company wanted to prevent competitors from using and abusing the name Docker for their own gains. This was the main reason why the Moby project was born. It serves as an umbrella for most of the open source components Docker developed and continues to develop. These open source projects do not carry the name Docker in them anymore.

The Moby project provides components that are used for image management, secret management, configuration management, and networking and provisioning, to name just a few. Also, part of the Moby project is special Moby tools that are, for example, used to assemble components into runnable artifacts.

Some components that technically belong to the Moby project have been donated by Docker to the Cloud-Native Computing Foundation (CNCF) and thus do not appear in the list of components anymore. The most prominent ones are notary, containerd, and runc, where the first is used for content trust and the latter two form the container runtime.

Docker products

Docker currently separates its product lines into two segments. There is the CommunityEdition (CE), which is closed-source yet completely free, and then there is the Enterprise Edition (EE), which is also closed-source and needs to be licensed on a yearly basis. These enterprise products are backed by 24/7 support and are supported by bug fixes.

Docker CE

Part of the Docker Community Edition are products such as the Docker Toolbox and Docker for Desktop with its editions for Mac and Windows. All these products are mainly targeted at developers.

Docker for Desktop is an easy-to-install desktop application that can be used to build, debug, and test Dockerized applications or services on a macOS or Windows machine. Docker for macOS and Docker for Windows are complete development environments that are deeply integrated with their respective hypervisor framework, network, and filesystem. These tools are the fastest and most reliable way to run Docker on a Mac or Windows.

Under the CE umbrella, there are also two products that are more geared toward operations engineers. These products are Docker for Azure and Docker for AWS.

For example, with Docker for Azure, which is a native Azure application, you can set up Docker in a few clicks, optimized for and integrated with underlying Azure Infrastructure as a Service (IaaS) services. It helps operations engineers accelerate time to productivity when building and running Docker applications in Azure.

Docker for AWS works very similarly but for Amazon's cloud.

Docker EE

The Docker Enterprise Edition consists of the Universal Control Plane (UCP) and the Docker Trusted Registry (DTR), both of which run on top of Docker Swarm. Both are swarm applications. Docker EE builds on top of the upstream components of the Moby project and adds enterprise-grade features such as role-based access control (RBAC), multi-tenancy, mixed clusters of Docker swarm and Kubernetes, web-based UI, and content trust, as well as image scanning on top.

Container architecture

Now, let's discuss how a system that can run Docker containers is designed at a high level. The following diagram illustrates what a computer that Docker has been installed on looks like. Note that a computer that has Docker installed on it is often called a Docker host because it can run or host Docker containers:

High-level architecture diagram of the Docker engine

In the preceding diagram, we can see three essential parts:

On the bottom, we have the

Linux operating system

In the middle, in dark gray, we have the container runtime

On the top, we have the

Docker engine

Containers are only possible due to the fact that the Linux OS provides some primitives, such as namespaces, control groups, layer capabilities, and more, all of which are leveraged in a very specific way by the container runtime and the Docker engine. Linux kernel namespaces, such as process ID (pid) namespaces or network (net) namespaces, allow Docker to encapsulate or sandbox processes that run inside the container. Control Groups make sure that containers cannot suffer from the noisy-neighbor syndrome, where a single application running in a container can consume most or all of the available resources of the whole Docker host. Control Groups allow Docker to limit the resources, such as CPU time or the amount of RAM, that each container is allocated.

The container runtime on a Docker host consists of containerd and runc. runc is the low-level functionality of the container runtime, while containerd, which is based on runc, provides higher-level functionality. Both are open source and have been donated by Docker to the CNCF.

The container runtime is responsible for the whole life cycle of a container. It pulls a container image (which is the template for a container) from a registry if necessary, creates a container from that image, initializes and runs the container, and eventually stops and removes the container from the system when asked.

The Docker engine provides additional functionality on top of the container runtime, such as network libraries or support for plugins. It also provides a REST interface over which all container operations can be automated. The Docker command-line interface that we will use frequently in this book is one of the consumers of this REST interface.

Summary

In this chapter, we looked at how containers can massively reduce friction in the software supply chain and, on top of that, make the supply chain much more secure.

In the next chapter, we will learn how to prepare our personal or working environment such as that we can work efficiently and effectively with Docker. So, stay tuned.

Questions

Please answer the following questions to assess your learning progress:

Which statements are correct (multiple answers are possible)?

A. A container is kind of a lightweight VM B. A container only runs on a Linux host C. A container can only run one process D. The main process in a container always has PID 1 E. A container is one or more processes encapsulated by Linux namespaces and restricted by cgroups

In your own words, maybe by using analogies, explain what a container is.

Why are containers considered to be a game-changer in IT? Name three or four reasons.

What does it mean when we claim:

If a container runs on a given platform, then it runs anywhere...?

Name two to three reasons why this is true.

Docker containers are only really useful for modern greenfield applications based on microservices. Please justify your answer.

A. True B. False

How much does a typical enterprise save when containerizing its legacy applications?

A. 20% B. 33% C. 50% D. 75%

Which two core concepts of Linux are containers based on?

Further reading

The following is a list of links that lead to more detailed information regarding the topics we discussed in this chapter:

Docker overview:

 

https://docs.docker.com/engine/docker-overview/

The Moby project:

https://mobyproject.org/

Docker products:

https://www.docker.com/get-started

Cloud-Native Computing Foundation: 

https://www.cncf.io/

containerd

– an

industry-standard container runtime: 

https://containerd.io/

Setting Up a Working Environment

In the last chapter, we learned what Docker containers are and why they're important. We learned what kinds of problems containers solve in a modern software supply chain.

In this chapter, we are going to prepare our personal or working environment to work efficiently and effectively with Docker. We will discuss in detail how to set up an ideal environment for developers, DevOps, and operators that can be used when working with Docker containers.

This chapter covers the following topics:

The Linux command shell

PowerShell for Windows

Installing and using a package manager

Installing Git and cloning the code repository

Choosing and installing a code editor

Installing Docker for Desktop on macOS or Windows

Installing Docker Toolbox

Installing Minikube

Technical requirements

For this chapter, you will need a laptop or a workstation with either macOS or Windows, preferably Windows 10 Professional, installed. You should also have free internet access to download applications and permission to install those applications on your laptop.

It is also possible to follow along with this book if you have a Linux distribution as your operating system, such as Ubuntu 18.04 or newer. I will try to indicate where commands and samples differ significantly from the ones on macOS or Windows.

The Linux command shell

Docker containers were first developed on Linux for Linux. It is hence natural that the primary command-line tool used to work with Docker, also called a shell, is a Unix shell; remember, Linux derives from Unix. Most developers use the Bash shell. On some lightweight Linux distributions, such as Alpine, Bash is not installed and consequently one has to use the simpler Bourne shell, just called sh. Whenever we are working in a Linux environment, such as inside a container or on a Linux VM, we will use either /bin/bash or /bin/sh, depending on their availability.

Although Apple's macOS X is not a Linux OS, Linux and macOS X are both flavors of Unix and hence support the same set of tools. Among those tools are the shells. So, when working on macOS, you will probably be using the Bash shell.

In this book, we expect from you a familiarity with the most basic scripting commands in Bash and PowerShell, if you are working on Windows. If you are an absolute beginner, then we strongly recommend that you familiarize yourself with the following cheat sheets:

Linux Command Line Cheat Sheet

 

by Dave Child at 

http://bit.ly/2mTQr8l

PowerShell Basic Cheat Sheet

 

at 

http://bit.ly/2EPHxze

PowerShell for Windows

On a Windows computer, laptop, or server, we have multiple command-line tools available. The most familiar is the command shell. It has been available on any Windows computer for decades. It is a very simple shell. For more advanced scripting, Microsoft has developed PowerShell. PowerShell is very powerful and very popular among engineers working on Windows. On Windows 10, finally, we have the so-called Windows Subsystem for Linux, which allows us to use any Linux tool, such as the Bash or Bourne shells. Apart from this, there are also other tools that install a Bash shell on Windows, for example, the Git Bash shell. In this book, all commands will use Bash syntax. Most of the commands also run in PowerShell.

Our recommendation for you is hence to either use PowerShell or any other Bash tool to work with Docker on Windows.

Using a package manager

The easiest way to install software on a macOS or Windows laptop is to use a good package manager. On macOS, most people use Homebrew, and on Windows, Chocolatey is a good choice. If you're using a Debian-based Linux distribution such as Ubuntu, then the package manager of choice for most is apt, which is installed by default. 

Installing Homebrew on macOS

Homebrew is the most popular package manager on macOS, and it is easy to use and very versatile. Installing Homebrew on macOS is simple; just follow the instructions at https://brew.sh/:

In a nutshell, open a new Terminal window and execute the

 

following

 

command to install Homebrew:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Once the installation is finished, test whether Homebrew is working by entering

 

brew --version

 

in the Terminal. You should see something like this:

$ brew --version

Homebrew 2.1.4Homebrew/homebrew-core (git revision 77d1b; last commit 2019-06-07)

Now, we are ready to use Homebrew to install tools and utilities. If we, for example, want to install the Vi text editor, we can do so like this:

$ brew install vim

This will then download and install the editor for you.

Installing Chocolatey on Windows

Chocolatey is a popular package manager for Windows, built on PowerShell. To install the Chocolatey package manager, please follow the instructions at https://chocolatey.org/ or open a new PowerShell window in admin mode and execute the following command:

PS> Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

It is important to run the preceding command as an administrator, otherwise, the installation will not succeed.

Once Chocolatey is installed, test it with the 

choco --version

 command. You should see output similar to the following:

PS> choco --version

0.10.15

To install an application such as the Vi editor, use the following command:

PS> choco install -y vim

The -y parameter makes sure that the installation happens without asking for reconfirmation.

Please note that once Chocolatey has installed an application, you need to open a new PowerShell window to use that application.

Installing Git

We are using Git to clone the sample code accompanying this book from its GitHub repository. If you already have Git installed on your computer, you can skip this section:

To install Git on your macOS, use the following command in a Terminal window:

$ choco install git

To install Git on Windows, open a PowerShell window and use Chocolatey to install it:

PS>

choco install git -y

Finally, on your Debian or Ubuntu machine, open a Bash console and execute the following command:

$ sudo apt update && sudo apt install -y git

Once Git is installed, verify that it is working. On all platforms, use the following:

$ git --version

This should output something along the lines of the following:

git version 2.16.3

Now that Git is working, we can clone the source code accompanying this book from GitHub. Execute the following command:

$ cd ~

$ git clone https://github.com/PacktPublishing/Learn-Docker---Fundamentals-of-Docker-19.x-Second-Edition fod-solution

This will clone the content of the master branch into your local folder, ~/fod-solution. This folder will now contain all of the sample solutions for the labs we are going to do together in this book. Refer to these sample solutions if you get stuck.

Now that we have installed the basics, let's continue with the code editor.

Choosing a code editor

Using a good code editor is essential to working productively with Docker. Of course, which editor is the best is highly controversial and depends on your personal preference. A lot of people use Vim, or others such as Emacs, Atom, Sublime, or Visual Studio Code (VS Code), to just name a few. VS Code is a completely free and lightweight editor, yet it is very powerful and is available for macOS, Windows, and Linux. According to Stack Overflow, it is currently by far the most popular code editor. If you are not yet sold on another editor, I highly recommend that you give VS Code a try.

But if you already have a favorite code editor, then please continue using it. As long as you can edit text files, you're good to go. If your editor supports syntax highlighting for Dockerfiles and JSON and YAML files, then even better. The only exception will be Chapter 6, Debugging Code Running in a Container. The examples presented in that chapter will be heavily tailored toward VS Code. 

Installing VS Code on macOS

Follow these steps for installation:

Open a new Terminal window and execute the following command:

$ brew cask install visual-studio-code

Once VS Code has been installed successfully, navigate to your home directory (

~

) and create a folder, 

fundamentals-of-docker

; then navigate into this new folder:

$ mkdir ~/fundamentals-of-docker && cd ~/fundamentals-of-docker

Now open VS Code from within this folder:

$ code .

Don't forget the period (.) in the preceding command. VS will start and open the current folder (~/fundamentals-of-docker) as the working folder.

Installing VS Code on Windows

Follow these steps for installation:

Open a new PowerShell window in admin mode and execute the following command:

PS>

choco install vscode -y

Close your PowerShell window and open a new one, to make sure VS Code is in your path.

Now navigate to your home directory and create a folder, 

fundamentals-of-docker

; then navigate into this new folder:

PS>

mkdir ~\fundamentals-of-docker; cd ~\fundamentals-of-docker

Finally open Visual Studio Code from within this folder:

PS>

code .

Don't forget the period (.) in the preceding command. VS will start and open the current folder (~\fundamentals-of-docker) as the working folder.

Installing VS Code on Linux

Follow these steps for installation:

On your Debian or Ubuntu-based Linux machine, open a Bash Terminal and execute the following statement to install VS Code:

$ sudo snap install --classic code

If you're using a Linux distribution that's not based on Debian or Ubuntu, then please follow the following link for more details: 

https://code.visualstudio.com/docs/setup/linux

Once VS Code has been installed successfully, navigate to your home directory (

~

) and create a folder

fundamentals-of-docker

; then navigate into this new folder:

$ mkdir ~/fundamentals-of-docker && cd ~/fundamentals-of-docker

Now open Visual Studio Code from within this folder:

$ code .

Don't forget the period (.) in the preceding command. VS will start and open the current folder (~/fundamentals-of-docker) as the working folder.

Installing VS Code extensions

Extensions are what make VS Code such a versatile editor. On all three platforms, macOS, Windows, and Linux, you can install VS Code extensions the same way: