Docker Remote API on CentOS

After installing Docker on CentOS we need to Docker remote API port on CentOS.

$ cat /etc/sysconfig/docker
other_args=""

Edit the file /etc/sysconfig/docker as below.

other_args="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock"

After that, restart docker and try to access the host from another host.

$ sudo /etc/init.d/docker restart
...
$ curl $hostname:4243/images/json
...

For a systemd based Distro like Centos7
Linux with systemd (Ubuntu 15.04, Debian 8,…)

Using systemd, we’ll need to enable a systemd socket to access the Docker remote API:

Create a new systemd config file called /etc/systemd/system/docker-tcp.socket to make docker available on a TCP socket on port 2375.

[Unit]
Description=Docker HTTP Socket for the API

[Socket]
ListenStream=2375
BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target
Register the new systemd http socket and restart docker
systemctl enable docker-tcp.socket
systemctl stop docker
systemctl start docker-tcp.socket

Open your browser and verify you can connect to http://localhost:2375/_ping

Enable the remote API on a new socket

Create a file called /etc/systemd/system/docker-tcp.socket to make Docker available on a TCP socket on port 2375.

<code><span class="nn">[Unit]</span>
<span class="py">Description</span><span class="p">=</span><span class="s">Docker Socket for the API</span>

<span class="nn">[Socket]</span>
<span class="py">ListenStream</span><span class="p">=</span><span class="s">2375</span>
<span class="py">BindIPv6Only</span><span class="p">=</span><span class="s">both</span>
<span class="py">Service</span><span class="p">=</span><span class="s">docker.service</span>

<span class="nn">[Install]</span>
<span class="py">WantedBy</span><span class="p">=</span><span class="s">sockets.target</span>
</code>

Then enable this new socket:

<code>systemctl <span class="nb">enable </span>docker-tcp.socket
systemctl stop docker
systemctl start docker-tcp.socket
systemctl start docker
</code>

Test that it’s working:

<code>docker -H tcp://127.0.0.1:2375 ps
</code>

Cloud-config

To enable the remote API on every CoreOS machine in a cluster, use cloud-config. We need to provide the new socket file and Docker’s socket activation support will automatically start using the socket:

<code><span class="c1">#cloud-config</span>

<span class="s">coreos</span><span class="pi">:</span>
  <span class="s">units</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker-tcp.socket</span>
      <span class="s">command</span><span class="pi">:</span> <span class="s">start</span>
      <span class="s">enable</span><span class="pi">:</span> <span class="s">true</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">[Unit]</span>
        <span class="no">Description=Docker Socket for the API</span>

        <span class="no">[Socket]</span>
        <span class="no">ListenStream=2375</span>
        <span class="no">BindIPv6Only=both</span>
        <span class="no">Service=docker.service</span>

        <span class="no">[Install]</span>
        <span class="no">WantedBy=sockets.target</span>
</code>

To keep access to the port local, replace the ListenStream configuration above with:

<code>        <span class="pi">[</span><span class="nv">Socket</span><span class="pi">]</span>
        <span class="s">ListenStream=127.0.0.1:2375</span>
</code>

Enable the remote API with TLS authentication

Docker TLS configuration consists of three parts: keys creation, configuring new systemd socket unit and systemddrop-in configuration.

TLS keys creation

Please follow the instruction to know how to create self-signed certificates and private keys. Then copy with following files into /etc/docker CoreOS’ directory and fix their permissions:

<code>scp ~/cfssl/<span class="o">{</span>server.pem,server-key.pem,ca.pem<span class="o">}</span> coreos.example.com:
ssh core@coreos.example.com
sudo mv <span class="o">{</span>server.pem,server-key.pem,ca.pem<span class="o">}</span> /etc/docker/
sudo chown root:root /etc/docker/<span class="o">{</span>server-key.pem,server.pem,ca.pem<span class="o">}</span>
sudo chmod 0600 /etc/docker/server-key.pem
</code>

On your local host copy certificates into ~/.docker:

<code>mkdir ~/.docker
chmod 700 ~/.docker
<span class="nb">cd</span> ~/.docker
cp -p ~/cfssl/ca.pem ca.pem
cp -p ~/cfssl/client.pem cert.pem
cp -p ~/cfssl/client-key.pem key.pem
</code>

Enable the secure remote API on a new socket

NOTE: For CoreOS releases older than 949.0.0 you must follow this guide.

Create a file called /etc/systemd/system/docker-tls-tcp.socket to make Docker available on a secured TCP socket on port 2376.

<code><span class="nn">[Unit]</span>
<span class="py">Description</span><span class="p">=</span><span class="s">Docker Secured Socket for the API</span>

<span class="nn">[Socket]</span>
<span class="py">ListenStream</span><span class="p">=</span><span class="s">2376</span>
<span class="py">BindIPv6Only</span><span class="p">=</span><span class="s">both</span>
<span class="py">Service</span><span class="p">=</span><span class="s">docker.service</span>

<span class="nn">[Install]</span>
<span class="py">WantedBy</span><span class="p">=</span><span class="s">sockets.target</span>
</code>

Then enable this new socket:

<code>systemctl <span class="nb">enable </span>docker-tls-tcp.socket
systemctl stop docker
systemctl start docker-tls-tcp.socket
</code>

Drop-in configuration

Create /etc/systemd/system/docker.service.d/10-tls-verify.conf drop-in for systemd Docker service:

<code><span class="nn">[Service]</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">"DOCKER_OPTS=--tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server.pem --tlskey=/etc/docker/server-key.pem"</span>
</code>

Reload systemd config files and restart docker service:

<code>sudo systemctl daemon-reload
sudo systemctl restart docker.service
</code>

Now you can access your Docker’s API through TLS secured connection:

<code>docker --tlsverify -H tcp://server:2376 images
<span class="c"># or</span>
docker --tlsverify -H tcp://server.example.com:2376 images
</code>

If you’ve experienceed problems connection to remote Docker API using TLS connection, you can debug it with curl:

<code>curl -v --cacert ~/.docker/ca.pem --cert ~/.docker/cert.pem --key ~/.docker/key.pem https://server:2376
</code>

Or on your CoreOS host:

<code>journalctl -f -u docker.service
</code>

In addition you can export environment variables and use docker client without additional options:

<code><span class="nb">export </span><span class="nv">DOCKER_HOST</span><span class="o">=</span>tcp://server.example.com:2376 <span class="nv">DOCKER_TLS_VERIFY</span><span class="o">=</span>1
docker images
</code>

Cloud-config

Cloud-config for Docker TLS authentication will look like:

<code><span class="c1">#cloud-config</span>

<span class="s">write_files</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">path</span><span class="pi">:</span> <span class="s">/etc/docker/ca.pem</span>
      <span class="s">permissions</span><span class="pi">:</span> <span class="s">0644</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">-----BEGIN CERTIFICATE-----</span>
        <span class="no">MIIFNDCCAx6gAwIBAgIBATALBgkqhkiG9w0BAQswLTEMMAoGA1UEBhMDVVNBMRAw</span>
        <span class="no">DgYDVQQKEwdldGNkLWNhMQswCQYDVQQLEwJDQTAeFw0xNTA5MDIxMDExMDhaFw0y</span>
        <span class="no">NTA5MDIxMDExMThaMC0xDDAKBgNVBAYTA1VTQTEQMA4GA1UEChMHZXRjZC1jYTEL</span>
        <span class="no">... ... ...</span>
    <span class="pi">-</span> <span class="s">path</span><span class="pi">:</span> <span class="s">/etc/docker/server.pem</span>
      <span class="s">permissions</span><span class="pi">:</span> <span class="s">0644</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">-----BEGIN CERTIFICATE-----</span>
        <span class="no">MIIFajCCA1SgAwIBAgIBBTALBgkqhkiG9w0BAQswLTEMMAoGA1UEBhMDVVNBMRAw</span>
        <span class="no">DgYDVQQKEwdldGNkLWNhMQswCQYDVQQLEwJDQTAeFw0xNTA5MDIxMDM3MDFaFw0y</span>
        <span class="no">NTA5MDIxMDM3MDNaMEQxDDAKBgNVBAYTA1VTQTEQMA4GA1UEChMHZXRjZC1jYTEQ</span>
        <span class="no">... ... ...</span>
    <span class="pi">-</span> <span class="s">path</span><span class="pi">:</span> <span class="s">/etc/docker/server-key.pem</span>
      <span class="s">permissions</span><span class="pi">:</span> <span class="s">0600</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">-----BEGIN RSA PRIVATE KEY-----</span>
        <span class="no">MIIJKAIBAAKCAgEA23Q4yELhNEywScrHl6+MUtbonCu59LIjpxDMAGxAHvWhWpEY</span>
        <span class="no">P5vfas8KgxxNyR+U8VpIjEXvwnhwCx/CSCJc3/VtU9v011Ir0WtTrNDocb90fIr3</span>
        <span class="no">YeRWq744UJpBeDHPV9opf8xFE7F74zWeTVMwtiMPKcQDzZ7XoNyJMxg1wmiMbdCj</span>
        <span class="no">... ... ...</span>
<span class="s">coreos</span><span class="pi">:</span>
  <span class="s">units</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker-tls-tcp.socket</span>
      <span class="s">command</span><span class="pi">:</span> <span class="s">start</span>
      <span class="s">enable</span><span class="pi">:</span> <span class="s">true</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">[Unit]</span>
        <span class="no">Description=Docker Secured Socket for the API</span>

        <span class="no">[Socket]</span>
        <span class="no">ListenStream=2376</span>
        <span class="no">BindIPv6Only=both</span>
        <span class="no">Service=docker.service</span>

        <span class="no">[Install]</span>
        <span class="no">WantedBy=sockets.target</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker.service</span>
      <span class="s">drop-ins</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">10-tls-verify.conf</span>
          <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="no">[Service]</span>
            <span class="no">Environment="DOCKER_OPTS=--tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server.pem --tlskey=/etc/docker/server-key.pem"</span>
</code>

Use attached storage for Docker images

Docker containers can be very large and debugging a build process makes it easy to accumulate hundreds of containers. It’s advantageous to use attached storage to expand your capacity for container images. Check out the guide to mounting storage to your CoreOS machine for an example of how to bind mount storage into /var/lib/docker.

Enabling the Docker debug flag

First, copy the existing unit from the read-only file system into the read/write file system, so we can edit it:

<code>cp /usr/lib/systemd/system/docker.service /etc/systemd/system/
</code>

Edit the ExecStart line to add the -D flag:

<code><span class="py">ExecStart</span><span class="p">=</span><span class="s">/usr/bin/docker -d -s=btrfs -r=false -H fd:// -D</span>
</code>

Now lets tell systemd about the new unit and restart Docker:

<code>systemctl daemon-reload
systemctl restart docker
</code>

To test our debugging stream, run a Docker command and then read the systemd journal, which should contain the output:

<code>docker ps
journalctl -u docker
</code>

Cloud-config

If you need to modify a flag across many machines, you can provide the new unit with cloud-config:

<code><span class="c1">#cloud-config</span>

<span class="s">coreos</span><span class="pi">:</span>
  <span class="s">units</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker.service</span>
      <span class="s">command</span><span class="pi">:</span> <span class="s">restart</span>
      <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="no">[Unit]</span>
        <span class="no">Description=Docker Application Container Engine</span>
        <span class="no">Documentation=http://docs.docker.io</span>
        <span class="no">After=network.target</span>
        <span class="no">[Service]</span>
        <span class="no">ExecStartPre=/bin/mount --make-rprivate /</span>
        <span class="no"># Run docker but don't have docker automatically restart</span>
        <span class="no"># containers. This is a job for systemd and unit files.</span>
        <span class="no">ExecStart=/usr/bin/docker -d -s=btrfs -r=false -H fd:// -D</span>

        <span class="no">[Install]</span>
        <span class="no">WantedBy=multi-user.target</span>
</code>

Use an HTTP proxy

If you’re operating in a locked down networking environment, you can specify an HTTP proxy for Docker to use via an environment variable. First, create a directory for drop-in configuration for Docker:

<code>mkdir /etc/systemd/system/docker.service.d
</code>

Now, create a file called /etc/systemd/system/docker.service.d/http-proxy.conf that adds the environment variable:

<code><span class="nn">[Service]</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">"HTTP_PROXY=http://proxy.example.com:8080"</span>
</code>

To apply the change, reload the unit and restart Docker:

<code>systemctl daemon-reload
systemctl restart docker
</code>

Cloud-config

The easiest way to use this proxy on all of your machines is via cloud-config:

<code><span class="c1">#cloud-config</span>

<span class="s">coreos</span><span class="pi">:</span>
  <span class="s">units</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker.service</span>
      <span class="s">drop-ins</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">20-http-proxy.conf</span>
          <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="no">[Service]</span>
            <span class="no">Environment="HTTP_PROXY=http://proxy.example.com:8080"</span>
      <span class="s">command</span><span class="pi">:</span> <span class="s">restart</span>
</code>

Increase ulimits

If you need to increase certain ulimits that are too low for your application by default, like memlock, you will need to modify the Docker service to increase the limit. First, create a directory for drop-in configuration for Docker:

<code>mkdir /etc/systemd/system/docker.service.d
</code>

Now, create a file called /etc/systemd/system/docker.service.d/increase-ulimit.conf that adds increased limit:

<code><span class="nn">[Service]</span>
<span class="py">LimitMEMLOCK</span><span class="p">=</span><span class="s">infinity</span>
</code>

To apply the change, reload the unit and restart Docker:

<code>systemctl daemon-reload
systemctl restart docker
</code>

Cloud-config

The easiest way to use these new ulimits on all of your machines is via cloud-config:

<code><span class="c1">#cloud-config</span>

<span class="s">coreos</span><span class="pi">:</span>
  <span class="s">units</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">docker.service</span>
      <span class="s">drop-ins</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">name</span><span class="pi">:</span> <span class="s">30-increase-ulimit.conf</span>
          <span class="s">content</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="no">[Service]</span>
            <span class="no">LimitMEMLOCK=infinity</span>
      <span class="s">command</span><span class="pi">:</span> <span class="s">restart</span>
</code>

Using a dockercfg file for authentication

A json file .dockercfg can be created in your home directory that holds authentication information for a public or private Docker registry.

Read more about registry authentication.

nJoy 😉

Leave a Reply

Your email address will not be published. Required fields are marked *