Join our Discord Server
Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 570+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 8900+ members and discord server close to 2200+ members. You can follow him on Twitter(@ajeetsraina).

DigitalOcean – A Perfect Docker Developer’s Cloud

3 min read

DigitalOcean (sweetly called “DO”) is “Docker Developer’s Platform”. If you’re a developer & looking out for speedy way to spin up your choice of virtual machine in less than 1 minute, DO is the right platform. With DO, you get chance to build more and spend less time managing your infrastructure with easy-to-use control panel and API.

I stumbled upon DO few weeks back and I have been quite impressed around its offerings. Developers love Droplets. These Droplets are Linux-based virtual machines (VMs) that run on top of virtualized hardware. Each Droplet you create is a new server you can use, either standalone or as part of a larger, cloud-based infrastructure. The DigitalOcean API lets you manage DigitalOcean resources programmatically using conventional HTTP requests. All the functionality available in the DigitalOcean Control Panel is also available through the API.

Doctl is Awesome..

DigitalOcean’s web-based control panel provides a point-and-click interface for managing Droplets. But as Droplets gets piled up, it might become tedious to manage & administer them, hence doctl is a great weapon which you can leverage. It is basically a Python wrapper for the Digital Ocean CLI utility. It is the official DigitalOcean command-line client. It uses the DigitalOcean API to provide access to most account and Droplet features.

Under this blog post, I will showcase how you can build and manage containerized workload on DigitalOcean in 5 Minutes.

Prerequisite:

  • Docker Desktop for Mac 2.1.7.0+
  • Install doctl – doctl is a command line interface for the DigitalOcean API.
brew install doctl

Method #1: Using doctl

[Captains-Bay]? >  doctl auth init
Using token [<>]

Validating token... OK

[Captains-Bay]? > 

Retrieving DO Account Information

[Captains-Bay]? >  doctl account get
Email                    Droplet Limit    Email Verified    UUID                                    Status
contact@collabnix.com    10               true              e1785fe2-d4f5-4d54-9e67-47dddddddddf46    active
[Captains-Bay]? >

Interacting with all your DO resources

doctl is able to interact with all of your DigitalOcean resources. Below are a few common usage examples.

[Captains-Bay]? >  doctl compute droplet list
ID    Name    Public IPv4    Private IPv4    Public IPv6    Memory    VCPUs    Disk    Region    Image    Status    Tags    Features    Volumes
[Captains-Bay]? >  

Creating a new Debian Instance

doctl compute droplet create test --size s-1vcpu-1gb    --image debian-10-x64 --region nyc1
[Captains-Bay]? >  doctl compute droplet list
ID           Name    Public IPv4        Private IPv4    Public IPv6    Memory    VCPUs    Disk    Region    Image              Status    Tags    Features    Volumes
171726228    test    206.189.207.163                                   1024      1        25      nyc1      Debian 10.0 x64    active    
[Captains-Bay]? >  doctl compute droplet list --format "ID,Name,PublicIPv4"
ID           Name    Public IPv4
171726228    test    206.189.207.163

Method-2: Using Docker Machine

  • Grab the token from DO site

Bring up Node #1

 docker-machine create --driver digitalocean --digitalocean-access-token 3xxxxxx49ab97229d node1
docker swarm init --advertise-addr <public_ip> --listen-addr <public_ip>

Bring up Node #2

 docker-machine create --driver digitalocean --digitalocean-access-token 3xxxxxff149ab97229d node2
docker swarm join <>

Using docker context

sudo systemctl edit docker.service

Add the below entry:

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://10.140.0.6:2375
sudo systemctl daemon-reload Restart Docker.
sudo systemctl restart docker.service
[Captains-Bay]? >  sudo docker context create --docker host=tcp://167.71.181.46:2375 mydot
mydot
Successfully created context "mydot"
[Captains-Bay]? >  sudo docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT               KUBERNETES ENDPOINT                                 ORCHESTRATOR
default *           Current DOCKER_HOST based configuration   unix:///var/run/docker.sock   https://kubernetes.docker.internal:6443 (default)   kubernetes
mydo                                                          tcp://68.183.148.254:2375                                                         
mydot                                                         tcp://167.71.181.46:2375                                                          
[Captains-Bay]? >  sudo docker context use mydot
mydot
Current context is now "mydot"
[Captains-Bay]? >  sudo docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
w7p4ezqbk13ks4y3sor4ppeml *   demo1               Ready               Active              Leader              19.03.5
dia0ylrodgbn0n1zcv7ckel8n     demo2               Ready               Active                                  19.03.5

As shown above, using Docker context CLI, one can now easily deploy containerized workload on remote DigitalOcean platform in just few seconds.

Deploying Redis 6.0 RC1 on 5 Node Swarm Cluster

I assume that 5-Node Swarm Cluster have been up and running on top of DO Platform.

Clone the Repository

git clone https://github.com/collabnix/dockerlabs
cd dockerlabs/solution/redis/viz-web-redis
docker stack deploy -c docker-compose.yml myredis

Verifying the Services

$ docker service ls
ID                  NAME                 MODE                REPLICAS            IMAGE                             PORTS
ydgp8j56apek        myredis_redis        replicated          1/1                 redis:3.0.6                       *:6379->6379/tcp
ofqnb4282zo1        myredis_visualizer   replicated          1/1                 dockersamples/visualizer:stable   *:8080->8080/tcp
bkxd3aklxhj7        myredis_web          replicated          5/5                 ajeetraina/redis-flask:latest     *:8000->8000/tcp

Verifying if redis is running successfully

$ docker service ps myredis_redis
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
robvimouagqj        myredis_redis.1     redis:6.0-rc1       manager1            Running             Running about a minute ago 

Verifying the Redis Volume

$ docker volume inspect myredis_data
[
    {
        "CreatedAt": "2019-12-29T02:18:00Z",
        "Driver": "local",
        "Labels": {
            "com.docker.stack.namespace": "myredis"
        },
        "Mountpoint": "/var/lib/docker/volumes/myredis_data/_data",
        "Name": "myredis_data",
        "Options": null,
        "Scope": "local"
    }
]

Checking the redis logs

[manager1] (local) root@192.168.0.45 ~/dockerlabs/solution/redis/viz-web-redis
$ docker service ps myredis_redis
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
robvimouagqj        myredis_redis.1     redis:6.0-rc1       manager1            Running             Running about a minute ago                       

Where is my redis service running?

$ docker service ps myredis_redis
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
robvimouagqj        myredis_redis.1     redis:6.0-rc1       manager1            Running             Running 3 minutes ago

Inspecting Redis Service

$ docker service inspect myredis_redis
[
    {
        "ID": "hmistkdxnirdm5vq2f41aaqr9",
        "Version": {
            "Index": 127
        },
        "CreatedAt": "2019-12-29T02:35:47.7810801Z",
        "UpdatedAt": "2019-12-29T02:35:47.78773254Z",
        "Spec": {
            "Name": "myredis_redis",
            "Labels": {
                "com.docker.stack.image": "redis:6.0-rc1",
                "com.docker.stack.namespace": "myredis"
            },
            "TaskTemplate": {
                "ContainerSpec": {
                    "Image": "redis:6.0-rc1@sha256:c2227b1e5c4755cb94f18eef10b34fb4eac116ce8c5ea0a40d0ca806927b8311",
                    "Labels": {
                        "com.docker.stack.namespace": "myredis"
                    },
                    "Args": [
                        "redis-server",
                        "--appendonly",
                        "yes"
                    ],
                    "Privileges": {
                        "CredentialSpec": null,
                        "SELinuxContext": null
                    },
                    "Mounts": [
                        {
                            "Type": "volume",
                            "Source": "myredis_data",
                            "Target": "/home/docker/data",
                            "VolumeOptions": {
                                "Labels": {
                                    "com.docker.stack.namespace": "myredis"
                                }
                            }
                        }
                    ],
                    "StopGracePeriod": 10000000000,
                    "DNSConfig": {},
                    "Isolation": "default"
                },
                "Resources": {},
                "RestartPolicy": {
                    "Condition": "any",
                    "Delay": 5000000000,
                    "MaxAttempts": 0
                },
                "Placement": {
                    "Constraints": [
                        "node.role == manager"
                    ],
                    "Platforms": [
                        {
                            "Architecture": "amd64",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "386",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "ppc64le",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "s390x",
                            "OS": "linux"
                        }
                    ]
                },
                "Networks": [
                    {
                        "Target": "rolenrgn8nqibx2h16wd2tac6",
                        "Aliases": [
                            "redis"
                        ]
                    }
                ],
                "ForceUpdate": 0,
                "Runtime": "container"
            },
            "Mode": {
                "Replicated": {
                    "Replicas": 1
                }
            },
            "UpdateConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "RollbackConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "EndpointSpec": {
                "Mode": "vip",
                "Ports": [
                    {
                        "Protocol": "tcp",
                        "TargetPort": 6379,
                        "PublishedPort": 6379,
                        "PublishMode": "ingress"
                    }
                ]
            }
        },
        "Endpoint": {
            "Spec": {
                "Mode": "vip",
                "Ports": [
                    {
                        "Protocol": "tcp",
                        "TargetPort": 6379,
                        "PublishedPort": 6379,
                        "PublishMode": "ingress"
                    }
                ]
            },
            "Ports": [
                {
                    "Protocol": "tcp",
                    "TargetPort": 6379,
                    "PublishedPort": 6379,
                    "PublishMode": "ingress"
                }
            ],
            "VirtualIPs": [
                {
                    "NetworkID": "sl1ecujt79razdyhjvmbohhjo",
                    "Addr": "10.255.0.26/16"
                },
                {
                    "NetworkID": "rolenrgn8nqibx2h16wd2tac6",
                    "Addr": "10.0.1.15/24"
                }
            ]
        }
    }
]

Browse to http://<IP>:8000 . Try refreshing “Hello World” page multiple times and it will display the number of times the page have been accessed. Cool, Isn’t it?

Conclusion: DO is a perfect Docker Developer tool which helps in rapidly provisioning one to thousands of Droplets running containerized workloads in seconds.

References:

Have Queries? Join https://launchpass.com/collabnix

Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 570+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 8900+ members and discord server close to 2200+ members. You can follow him on Twitter(@ajeetsraina).
Join our Discord Server
Index