Docker
Installing Docker
brew cask install docker
Installing Kitematic
You can install Kitematic from your terminal running: brew cask install kitematic
Create a Private Docker Registry
Installing Package for Added Security
We'll install the apache2-utils package which contains the htpasswd utility that can easily generate password hashes Nginx can understand:
sudo apt-get -y install apache2-utilsInstalling and Configuring the Docker Registry
Docker Compose allows you to write one .yml configuration file for the configuration for each container
First create a folder where our files for this tutorial will live and some of the subfolders we'll need:
mkidr ~/docker-registry && cd $_
mkdir dataUsing your favorite text editor, create a docker-compose.yml file:
nano docker-compose.ymlAdd the following contents to the file:
version: '2'
services:
registry:
hostname: registry
restart: unless-stopped
image: registry:2
ports:
- 127.0.0.1:5000:5000
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./data:/data
networks:
- registry_platform
networks:
traefik_proxy:
external: true
registry_platform:
external: false
driver: bridgeDocker registry's data all gets stored in ~/docker-registry/data on our local machine.
Setting Up an Nginx Container
Let's get to work on fixing these security issues. The first step is to set up a copy of Nginx inside another Docker container and link it up to our Docker registry container.
Let's start by creating a directory to store our Nginx configuration:
mkdir ~/docker-registry/nginxNow, re-open your docker-compose.yml file in the ~/docker-registry directory:
Add a service on top of the registry service:
version: '2'
services:
nginx:
restart: unless-stopped
image: "nginx:1.9"
ports:
- 5043:443
volumes:
- ./nginx:/etc/nginx/conf.d:ro
labels:
- traefik.backend=registry
- traefik.docker.network=traefik_proxy
- traefik.frontend.rule=Host:registry.daton.it,docker-registry.daton.it
- traefik.port=443
networks:
- traefik_proxy
- registry_platformYour full docker-compose.yml file should now look like this:
version: '2'
services:
nginx:
restart: unless-stopped
image: "nginx:1.9"
ports:
- 5043:443
volumes:
- ./nginx:/etc/nginx/conf.d:ro
labels:
- traefik.backend=registry
- traefik.docker.network=traefik_proxy
- traefik.frontend.rule=Host:registry.yourdomain.com
- traefik.port=443
networks:
- traefik_proxy
- registry_platform
registry:
hostname: registry
restart: unless-stopped
image: registry:2
ports:
- 127.0.0.1:5000:5000
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
volumes:
- ./data:/data
networks:
- registry_platform
networks:
traefik_proxy:
external: true
registry_platform:
external: false
driver: bridgeWe need to configure Nginx before this will work though, so let's create a new Nginx configuration file.
Create a registry.conf file:
nano ~/docker-registry/nginx/registry.confCopy the following into the file:
upstream docker-registry {
server registry:5000;
}
server {
listen 443;
server_name myregistrydomain.com;
# SSL
# ssl on;
# ssl_certificate /etc/nginx/conf.d/domain.crt;
# ssl_certificate_key /etc/nginx/conf.d/domain.key;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
location /v2/ {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
# To add basic authentication to v2 use auth_basic setting plus add_header
# auth_basic "registry.localhost";
# auth_basic_user_file /etc/nginx/conf.d/registry.password;
# add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;
proxy_pass http://docker-registry;
proxy_set_header Host $http_host; # required for docker client's sake
# Since we are using Nginx behind Traefik we don't need these headers
# proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}Save and exit the file.
Now you can install Nginx and start up the two Docker containers all with one command:
docker-compose upFirst, make an HTTP request directly to the Docker registry:
curl http://localhost:5000/v2/As of this writing Docker returns an empty json object, so you should see:
{}Now send an HTTP request to the Nginx port:
curl http://localhost:5043/v2/You should see the same output:
{}Setting Up Authentication
Set up HTTP authentication so that we can control who has access to our Docker registry. To do that we'll create an authentication file in Apache format (Nginx can read it too) via the htpasswd utility we installed earlier and add users to it.
Create the first user as follows, replacing USERNAME with the username you want to use:
cd ~/docker-registry/nginx
htpasswd -c registry.password USERNAMECreate a new password for this user when prompted.
If you want to add more users in the future, just re-run the above command without the -c option (the cis for create):
htpasswd registry.password USERNAMEAt this point we have a registry.password file with our users set up and a Docker registry available. You can take a peek at the file at any point if you want to view your users (and remove users if you want to revoke access).
Next, we need to tell Nginx to use that authentication file.
Open up ~/docker-registry/nginx/registry.conf in your favorite text editor:
nano ~/docker-registry/nginx/registry.confUncomment the two lines that start with auth_basic as well as the line that starts with add_header by removing the # character at the beginning
of the lines. It should then look like this:~/docker-registry/nginx/registry.conf
# To add basic authentication to v2 use auth_basic setting plus add_header
auth_basic "registry.localhost";
auth_basic_user_file /etc/nginx/conf.d/registry.password;
add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;We've now told Nginx to enable HTTP basic authentication for all requests that get proxied to the Docker registry and told it to use the password file we just created.
Let's bring our containers back up to see if authentication is working:
cd ~/docker-registry
docker-compose upRepeat the previous curl test:
curl http://localhost:5043/v2/You should get a message complaining about being unauthorized:
Output of curl<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.9.7</center>
</body>
</html>Now try adding the username and password you created earlier to the curl request:
curl http://USERNAME:PASSWORD@localhost:5043/v2/You should get the same output you were getting before — the empty json object {}. You should also see the same registry_ output in the docker-compose terminal.
Go ahead and use CTRL-C in the docker-compose terminal to shut down the Docker containers.
Starting Docker Registry as a Service
Let's go ahead and start it up to make sure everything is in order:
cd ~/docker-registry
docker-compose rm # this removes the existing containers
docker-compose up -dIf everything went well you should have your Docker Registry up and running.
Publish to your Private Docker Registry
From your client machine, create a small empty image to push to our new registry.
docker run -t -i ubuntu /bin/bashAfter it finishes downloading you'll be inside a Docker prompt. Let's make a quick change to the filesystem by creating a file called SUCCESS:
touch /SUCCESSExit out of the Docker container:
exitCommit the change:
docker commit $(docker ps -lq) test-imageLog in to your registry:
docker login https://YOUR-DOMAINEnter the username and password you set up earlier, now let's tag our image to our private registry:
docker tag test-image [YOUR-DOMAIN]/test-imageNote that you are using the local name of the image first, then the tag you want to add to it. The tag does not use https://, just the domain, port, and image name.
Now we can push that image to our registry. This time we're using the tag name only:
docker push [YOUR-DOMAIN]/test-imagePull from Your Docker Registry
To make sure everything worked, let's go back to our original server (where you installed the Docker registry) and pull the image we just pushed from the client. You could also test this from a third server.
If Docker is not installed on your test pull server, go back and follow the installation instructions (and if it's a third server, the SSL instructions) from Step 6.
Log in with the username and password you set up previously.
docker login https://[YOUR-DOMAIN]And now pull the image. You want just the "tag" image name, which includes the domain name, port, and image name (but not https://):
docker pull [YOUR-DOMAIN]/test-imageDocker Registry Manager
We can install a useful manager like this:
We just need to clone the repo and edit the registry.yml file, then run docker-compose up -d and go to http://localhost:8080
Last updated