Setup Docker Container

See full list on Install docker-ce. Sudo apt-get update sudo apt-get install docker-ce docker-ce-cli Note: '' is independent of docker but included in that repository. Check docker, sudo docker run -rm hello-world. That should pull and run the hello-world container from Docker Hub. At this point only 'root' can run docker.


Orientation and setup. Estimated reading time: 4 minutes. We are excited that you want to learn Docker. This page contains step-by-step instructions on how to get started with Docker. In this tutorial, you’ll learn how to: Build and run an image as a container. Share images using Docker Hub. Deploy Docker applications using multiple.

This step-by-step guide will help you get started developing with remote containers by setting up Docker Desktop for Windows with WSL 2 (Windows Subsystem for Linux, version 2).

Docker Desktop for Windows provides a development environment for building, shipping, and running dockerized apps. By enabling the WSL 2 based engine, you can run both Linux and Windows containers in Docker Desktop on the same machine. (Docker Desktop is free for personal use and small businesses, for info on Pro, Team, or Business pricing, see the Docker site FAQs).

Overview of Docker containers

Docker is a tool used to create, deploy, and run applications using containers. Containers enable developers to package an app with all of the parts it needs (libraries, frameworks, dependencies, etc) and ship it all out as one package. Using a container ensures that the app will run the same regardless of any customized settings or previously installed libraries on the computer running it that could differ from the machine that was used to write and test the app's code. This permits developers to focus on writing code without worrying about the system that code will be run on.

Docker containers are similar to virtual machines, but don't create an entire virtual operating system. Instead, Docker enables the app to use the same Linux kernel as the system that it's running on. This allows the app package to only require parts not already on the host computer, reducing the package size and improving performance.

Continuous availability, using Docker containers with tools like Kubernetes, is another reason for the popularity of containers. This enables multiple versions of your app container to be created at different times. Rather than needing to take down an entire system for updates or maintenance, each container (and it's specific microservices) can be replaced on the fly. You can prepare a new container with all of your updates, set up the container for production, and just point to the new container once it's ready. You can also archive different versions of your app using containers and keep them running as a safety fallback if needed.

To learn more, checkout the Introduction to Docker containers on Microsoft Learn.


  • Ensure your machine is running Windows 10, updated to version 2004, Build 18362 or higher.
  • Install WSL and set up a user name and password for your Linux distribution running in WSL 2.
  • Install Visual Studio Code(optional). This will provide the best experience, including the ability to code and debug inside a remote Docker container and connected to your Linux distribution.
  • Install Windows Terminal(optional). This will provide the best experience, including the ability to customize and open multiple terminals in the same interface (including Ubuntu, Debian, PowerShell, Azure CLI, or whatever you prefer to use).
  • Sign up for a Docker ID at Docker Hub(optional).


WSL can run distributions in both WSL version 1 or WSL 2 mode. You can check this by opening PowerShell and entering: wsl -l -v. Ensure that the your distribution is set to use WSL 2 by entering: wsl --set-version <distro> 2. Replace <distro> with the distro name (e.g. Ubuntu 18.04).

In WSL version 1, due to fundamental differences between Windows and Linux, the Docker Engine couldn't run directly inside WSL, so the Docker team developed an alternative solution using Hyper-V VMs and LinuxKit. However, since WSL 2 now runs on a Linux kernel with full system call capacity, Docker can fully run in WSL 2. This means that Linux containers can run natively without emulation, resulting in better performance and interoperability between your Windows and Linux tools.

Install Docker Desktop

With the WSL 2 backend supported in Docker Desktop for Windows, you can work in a Linux-based development environment and build Linux-based containers, while using Visual Studio Code for code editing and debugging, and running your container in the Microsoft Edge browser on Windows.

To install Docker (after already installing WSL):

  1. Download Docker Desktop and follow the installation instructions.

  2. Once installed, start Docker Desktop from the Windows Start menu, then select the Docker icon from the hidden icons menu of your taskbar. Right-click the icon to display the Docker commands menu and select 'Settings'.

  3. Ensure that 'Use the WSL 2 based engine' is checked in Settings > General.

  4. Select from your installed WSL 2 distributions which you want to enable Docker integration on by going to: Settings > Resources > WSL Integration.

  5. To confirm that Docker has been installed, open a WSL distribution (e.g. Ubuntu) and display the version and build number by entering: docker --version

  6. Test that your installation works correctly by running a simple built-in Docker image using: docker run hello-world


Here are a few helpful Docker commands to know:

  • List the commands available in the Docker CLI by entering: docker
  • List information for a specific command with: docker <COMMAND> --help
  • List the docker images on your machine (which is just the hello-world image at this point), with: docker image ls --all
  • List the containers on your machine, with: docker container ls --all or docker ps -a (without the -a show all flag, only running containers will be displayed)
  • List system-wide information regarding the Docker installation, including statistics and resources (CPU & memory) available to you in the WSL 2 context, with: docker info › docker-tutorial-how-install-andDocker Tutorial: How to Install and Use Containers

Develop in remote containers using VS Code

To get started developing apps using Docker with WSL 2, we recommend using VS Code, along with the Remote-WSL extension and Docker extension.

  • Install the VS Code Remote-WSL extension. This extension enables you to open your Linux project running on WSL in VS Code (no need to worry about pathing issues, binary compatibility, or other cross-OS challenges).

  • Install the VS code Remote-Containers extension. This extension enables you to open your project folder or repo inside of a container, taking advantage of Visual Studio Code's full feature set to do your development work within the container.

  • Install the VS Code Docker extension. This extension adds the functionality to build, manage, and deploy containerized applications from inside VS Code. (You need the Remote-Container extension to actually use the container as your dev environment.)

Let's use Docker to create a development container for an existing app project.

  1. For this example, I'll use the source code from my Hello World tutorial for Django in the Python development environment set up docs. You can skip this step if you prefer to use your own project source code. To download my HelloWorld-Django web app from GitHub, open a WSL terminal (Ubuntu for example) and enter: git clone


    Always store your code in the same file system that you're using tools in. This will result in faster file access performance. In this example, we are using a Linux distro (Ubuntu) and want to store our project files on the WSL file system wsl. Storing project files on the Windows file system would significantly slow things down when using Linux tools in WSL to access those files.

  2. From your WSL terminal, change directories to the source code folder for this project:

  3. Open the project in VS Code running on the local Remote-WSL extension server by entering:

    Confirm that you are connected to your WSL Linux distro by checking the green remote indicator in the bottom-left corner of your VS Code instance.

  4. From the VS Code command pallette (Ctrl + Shift + P), enter: Remote-Containers: Open Folder in Container... If this command doesn't display as you begin to type it, check to ensure that you've installed the Remote Container extension linked above.

  5. Select the project folder that you wish to containerize. In my case, this is wslUbuntu-20.04homemattwojoreposhelloworld-django

  6. A list of container definitions will appear, since there is no DevContainer configuration in the project folder (repo) yet. The list of container configuration definitions that appears is filtered based on your project type. For my Django project, I'll select Python 3.

  7. A new instance of VS Code will open, begin building our new image, and once the build completed, will start our container. You will see that a new .devcontainer folder has appeared with container configuration information inside a Dockerfile and devcontainer.json file.

  8. To confirm that your project is still connected to both WSL and within a container, open the VS Code integrated terminal (Ctrl + Shift + ~). Check the operating system by entering: uname and the Python version with: python3 --version. You can see that the uname came back as 'Linux', so you are still connected to the WSL 2 engine, and Python version number will be based on the container config that may differ from the Python version installed on your WSL distribution.

  9. To run and debug your app inside of the container using Visual Studio Code, first open the Run menu (Ctrl+Shift+D or select the tab on the far left menu bar). Then select Run and Debug to select a debug configuration and choose the configuration that best suites your project (in my example, this will be 'Django'). This will create a launch.json file in the .vscode folder of your project with instructions on how to run your app.

  10. From inside VS Code, select Run > Start debugging (or just press the F5 key). This will open a terminal inside VS Code and you should see a result saying something like: 'Starting development server at Quit the server with CONTROL-C.' Hold down the Control key and select the address displayed to open your app in your default web browser and see your project running inside of its container.

You have now successfully configured a remote development container using Docker Desktop, powered by the WSL 2 backend, that you can code in, build, run, deploy, or debug using VS Code!


WSL docker context deprecated

If you were using an early Tech Preview of Docker for WSL, you may have a Docker context called 'wsl' that is now deprecated and no longer used. You can check with the command: docker context ls. You can remove this 'wsl' context to avoid errors with the command: docker context rm wsl as you want to use the default context for both Windows and WSL2.

Possible errors you might encounter with this deprecated wsl context include: docker wsl open //./pipe/docker_wsl: The system cannot find the file specified. or error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_wsl/v1.40/images/json?all=1: open //./pipe/docker_wsl: The system cannot find the file specified.

For more on this issue, see How to set up Docker within Windows System for Linux (WSL2) on Windows 10.

Trouble finding docker image storage folder

Docker creates two distro folders to store data:

  • wsl$docker-desktop
  • wsl$docker-desktop-data

You can find these folders by opening your WSL Linux distribution and entering: explorer.exe . to view the folder in Windows File Explorer. Enter: wsl<distro name>mntwsl replacing <distro name> with the name of your distribution (ie. Ubuntu-20.04) to see these folders.

Find more on locating docker storage locations in WSL, see this issue from the WSL repo or this StackOverlow post.

For more help with general troubleshooting issues in WSL, see the Troubleshooting doc.

Additional resources

Estimated reading time: 18 minutes

This page contains information about hosting your own registry using theopen source Docker Registry. For information about Docker Hub, which offers ahosted registry with additional features such as teams, organizations, webhooks, automated builds, etc, see Docker Hub.

Before you can deploy a registry, you need to install Docker on the host.A registry is an instance of the registry image, and runs within Docker.

This topic provides basic information about deploying and configuring aregistry. For an exhaustive list of configuration options, see theconfiguration reference.

If you have an air-gapped datacenter, seeConsiderations for air-gapped registries.

Run a local registry

Use a command like the following to start the registry container:

The registry is now ready to use.

Warning: These first few examples show registry configurations that areonly appropriate for testing. A production-ready registry must be protected byTLS and should ideally use an access-control mechanism. Keep reading and thencontinue to the configuration guide to deploy aproduction-ready registry.

Copy an image from Docker Hub to your registry

You can pull an image from Docker Hub and push it to your registry. Thefollowing example pulls the ubuntu:16.04 image from Docker Hub and re-tags itas my-ubuntu, then pushes it to the local registry. Finally, theubuntu:16.04 and my-ubuntu images are deleted locally and themy-ubuntu image is pulled from the local registry.

  1. Pull the ubuntu:16.04 image from Docker Hub.

  2. Tag the image as localhost:5000/my-ubuntu. This creates an additional tagfor the existing image. When the first part of the tag is a hostname andport, Docker interprets this as the location of a registry, when pushing.

  3. Push the image to the local registry running at localhost:5000:

  4. Remove the locally-cached ubuntu:16.04 and localhost:5000/my-ubuntuimages, so that you can test pulling the image from your registry. Thisdoes not remove the localhost:5000/my-ubuntu image from your registry.

  5. Pull the localhost:5000/my-ubuntu image from your local registry.

Stop a local registry

To stop the registry, use the same docker container stop command as with any othercontainer.

To remove the container, use docker container rm.

Basic configuration

To configure the container, you can pass additional or modified options to thedocker run command.

The following sections provide basic guidelines for configuring your registry.For more details, see the registry configuration reference.

Start the registry automatically

If you want to use the registry as part of your permanent infrastructure, youshould set it to restart automatically when Docker restarts or if it exits.This example uses the --restart always flag to set a restart policy for theregistry.

Customize the published port

If you are already using port 5000, or you want to run multiple localregistries to separate areas of concern, you can customize the registry’sport settings. This example runs the registry on port 5001 and also names itregistry-test. Remember, the first part of the -p value is the host portand the second part is the port within the container. Within the container, theregistry listens on port 5000 by default.

If you want to change the port the registry listens on within the container, youcan use the environment variable REGISTRY_HTTP_ADDR to change it. This commandcauses the registry to listen on port 5001 within the container:

Storage customization

Customize the storage location

By default, your registry data is persisted as a docker volumeon the host filesystem. If you want to store your registry contents at a specificlocation on your host filesystem, such as if you have an SSD or SAN mounted intoa particular directory, you might decide to use a bind mount instead. A bind mountis more dependent on the filesystem layout of the Docker host, but more performantin many situations. The following example bind-mounts the host directory/mnt/registry into the registry container at /var/lib/registry/.

Customize the storage back-end

By default, the registry stores its data on the local filesystem, whether youuse a bind mount or a volume. You can store the registry data in an Amazon S3bucket, Google Cloud Platform, or on another storage back-end by usingstorage drivers. For more information, seestorage configuration options.

Run an externally-accessible registry

Running a registry only accessible on localhost has limited usefulness. Inorder to make your registry accessible to external hosts, you must first secureit using TLS.

This example is extended in Run the registry as aservice below.

Get a certificate

These examples assume the following:

  • Your registry URL is
  • Your DNS, routing, and firewall settings allow access to the registry’s hoston port 443.
  • You have already obtained a certificate from a certificate authority (CA).

If you have been issued an intermediate certificate instead, seeuse an intermediate certificate.

  1. Create a certs directory.

    Copy the .crt and .key files from the CA into the certs directory.The following steps assume that the files are named domain.crt anddomain.key.

  2. Stop the registry if it is currently running.

  3. Restart the registry, directing it to use the TLS certificate. This commandbind-mounts the certs/ directory into the container at /certs/, and setsenvironment variables that tell the container where to find the domain.crtand domain.key file. The registry runs on port 443, the default HTTPS port.

  4. Docker clients can now pull from and push to your registry using itsexternal address. The following commands demonstrate this:

Use an intermediate certificate

A certificate issuer may supply you with an intermediate certificate. In thiscase, you must concatenate your certificate with the intermediate certificate toform a certificate bundle. You can do this using the cat command:

You can use the certificate bundle just as you use the domain.crt file inthe previous example.

Support for Let’s Encrypt

The registry supports using Let’s Encrypt to automatically obtain abrowser-trusted certificate. For more information on Let’s Encrypt, see the relevant section of theregistry configuration.

Use an insecure registry (testing only)

It is possible to use a self-signed certificate, or to use our registryinsecurely. Unless you have set up verification for your self-signedcertificate, this is for testing only. See run an insecure registry.

Run the registry as a service

Swarm services provide several advantages overstandalone containers. They use a declarative model, which means that you definethe desired state and Docker works to keep your service in that state. Servicesprovide automatic load balancing scaling, and the ability to control thedistribution of your service, among other advantages. Services also allow you tostore sensitive data such as TLS certificates insecrets.

The storage back-end you use determines whether you use a fully scaled serviceor a service with either only a single node or a node constraint.

  • If you use a distributed storage driver, such as Amazon S3, you can use afully replicated service. Each worker can write to the storage back-endwithout causing write conflicts.

  • If you use a local bind mount or volume, each worker node writes to itsown storage location, which means that each registry contains a differentdata set. You can solve this problem by using a single-replica service and anode constraint to ensure that only a single worker is writing to the bindmount.

The following example starts a registry as a single-replica service, which isaccessible on any swarm node on port 80. It assumes you are using the sameTLS certificates as in the previous examples.

First, save the TLS certificate and key as secrets:

Next, add a label to the node where you want to run the registry.To get the node’s name, use docker node ls. Substitute your node’s name fornode1 below.

Next, create the service, granting it access to the two secrets and constrainingit to only run on nodes with the label registry=true. Besides the constraint,you are also specifying that only a single replica should run at a time. Theexample bind-mounts /mnt/registry on the swarm node to /var/lib/registry/within the container. Bind mounts rely on the pre-existing source directory,so be sure /mnt/registry exists on node1. You might need to create it beforerunning the following docker service create command.

By default, secrets are mounted into a service at /run/secrets/<secret-name>.

You can access the service on port 443 of any swarm node. Docker sends therequests to the node which is running the service.

Load balancing considerations

One may want to use a load balancer to distribute load, terminate TLS orprovide high availability. While a full load balancing setup is outside thescope of this document, there are a few considerations that can make the processsmoother.

The most important aspect is that a load balanced cluster of registries mustshare the same resources. For the current version of the registry, this meansthe following must be the same:

  • Storage Driver
  • HTTP Secret
  • Redis Cache (if configured)

Differences in any of the above cause problems serving requests.As an example, if you’re using the filesystem driver, all registry instancesmust have access to the same filesystem root, onthe same machine. For other drivers, such as S3 or Azure, they should beaccessing the same resource and share an identical configuration.The HTTP Secret coordinates uploads, so also must be the same acrossinstances. Configuring different redis instances works (at the timeof writing), but is not optimal if the instances are not shared, becausemore requests are directed to the backend.

Important/Required HTTP-Headers

Getting the headers correct is very important. For all responses to anyrequest under the “/v2/” url space, the Docker-Distribution-API-Versionheader should be set to the value “registry/2.0”, even for a 4xx response.This header allows the docker engine to quickly resolve authentication realmsand fallback to version 1 registries, if necessary. Confirming this is setupcorrectly can help avoid problems with fallback.

In the same train of thought, you must make sure you are properly sending theX-Forwarded-Proto, X-Forwarded-For, and Host headers to their “client-side”values. Failure to do so usually makes the registry issue redirects to internalhostnames or downgrading from https to http.

A properly secured registry should return 401 when the “/v2/” endpoint is hitwithout credentials. The response should include a WWW-Authenticatechallenge, providing guidance on how to authenticate, such as with basic author a token service. If the load balancer has health checks, it is recommendedto configure it to consider a 401 response as healthy and any other as down.This secures your registry by ensuring that configuration problems withauthentication don’t accidentally expose an unprotected registry. If you’reusing a less sophisticated load balancer, such as Amazon’s Elastic LoadBalancer, that doesn’t allow one to change the healthy response code, healthchecks can be directed at “/”, which always returns a 200 OK response.

Restricting access

Except for registries running on secure local networks, registries should alwaysimplement access restrictions.

Native basic auth

The simplest way to achieve access restriction is through basic authentication(this is very similar to other web servers’ basic authentication mechanism).This example uses native basic authentication using htpasswd to store thesecrets.

Warning:You cannot use authentication with authentication schemes that sendcredentials as clear text. You mustconfigure TLS first forauthentication to work.

  1. Create a password file with one entry for the user testuser, with passwordtestpassword:

    On Windows, make sure the output file is correctly encoded:

  2. Stop the registry.

  3. Start the registry with basic authentication.

  4. Try to pull an image from the registry, or push an image to the registry.These commands fail.

  5. Log in to the registry.

    Provide the username and password from the first step.

    Test that you can now pull an image from the registry or push an image tothe registry.

X509 errors: X509 errors usually indicate that you are attempting to usea self-signed certificate without configuring the Docker daemon correctly.See run an insecure registry.

More advanced authentication

You may want to leverage more advanced basic auth implementations by using aproxy in front of the registry. See the recipes list.

The registry also supports delegated authentication which redirects users to aspecific trusted token server. This approach is more complicated to set up, andonly makes sense if you need to fully configure ACLs and need more control overthe registry’s integration into your global authorization and authenticationsystems. Refer to the following background information andconfiguration information here.

This approach requires you to implement your own authentication system orleverage a third-party implementation.

Deploy your registry using a Compose file

If your registry invocation is advanced, it may be easier to use a Dockercompose file to deploy it, rather than relying on a specific docker runinvocation. Use the following example docker-compose.yml as a template.

Replace /path with the directory which contains the certs/ and auth/directories.

Start your registry by issuing the following command in the directory containingthe docker-compose.yml file:

Considerations for air-gapped registries

You can run a registry in an environment with no internet connectivity.However, if you rely on any images which are not local, you need to consider thefollowing:

Run Docker Container As User

  • You may need to build your local registry’s data volume on a connectedhost where you can run docker pull to get any images which are availableremotely, and then migrate the registry’s data volume to the air-gappednetwork.

  • Certain images, such as the official Microsoft Windows base images, are notdistributable. This means that when you push an image based on one of theseimages to your private registry, the non-distributable layers are notpushed, but are always fetched from their authorized location. This is finefor internet-connected hosts, but not in an air-gapped set-up.

    You can configure the Docker daemon to allow pushing non-distributable layers to private registries.This is only useful in air-gapped set-ups in the presence ofnon-distributable images, or in extremely bandwidth-limited situations.You are responsible for ensuring that you are in compliance with the terms ofuse for non-distributable layers.

    1. Edit the daemon.json file, which is located in /etc/docker/ on Linuxhosts and C:ProgramDatadockerconfigdaemon.json on Windows Server.Assuming the file was previously empty, add the following contents:

      The value is an array of registry addresses, separated by commas.

      Save and exit the file.

    2. Restart Docker.

    3. Restart the registry if it does not start automatically.

    4. When you push images to the registries in the list, theirnon-distributable layers are pushed to the registry.

      Warning: Non-distributable artifacts typically have restrictions onhow and where they can be distributed and shared. Only use this featureto push artifacts to private registries and ensure that you are incompliance with any terms that cover redistributing non-distributableartifacts.

Docker Setup Rabbitmq Container

Next steps

Run Docker Container As Root

More specific and advanced information is available in the following sections: › Wsl › TutorialsGet Started With Docker Containers On WSL Microsoft Docs

registry, on-prem, images, tags, repository, distribution, deployment