Docker is a powerful tool, however learning how to use it the right way could take a long time especially with the rapidly growing ecosystem of containers which could be confusing, that is why I had the idea to start writing . Painless Docker is a complete and detailed guide (for beginners and intermediate levels) to , , , , , , , & Docker and Docker clusters in order to create a high quality microservices applications. Painless Docker create deploy optimize secure trace debug log orchestrate monitor This article is more detailed in the of . bonus chapters Painless Docker Book Using Docker, Docker Swarm, Amazon RDS (Aurora) + EC2, GlusterFS & Traefik, we are going to create a highly available and scalable WordPress cluster. Preparing The Infrastructure I am using Amazon machines but you can use you prefered infrastructure. EC2 Start by creating two ( machines . EC2) in two different availability zones In this tutorial, I am using: eu-west-1aeu-west-1b The first machine will be the of the Swarm cluster and the second one will be the . manager worker but it depends on how available you want your cluster to be, . This is just an example you may create 3 managers (or more) for more availability The manager will have a public because it will receive all of the ingoing requests and redirect them to Docker that will handle the internal load balancing between the containers living in the (same machine in this case) and the containers living in the . IP manager worker Don’t forget to add an to each machine. Elastic Block Store We should have two instances: Using , we can verify that the is attached to our machine: lsbsk EBS NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTxvda 202:0 0 8G 0 disk `-xvda1 202:1 0 8G 0 part /xvdb 202:16 0 10G 0 disk On each machine, create our : filesystem sudo mkfs.xfs /dev/xvdb Creating A Trusted Pool Using GlusterFS GlusterFS is a scale-out network-attached storage file system. Using common off-the-shelf hardware, you can create large, distributed storage solutions for media streaming, data analysis, and other data- and bandwidth-intensive tasks. GlusterFS was developed originally by Gluster, Inc. and then by Red Hat, Inc., as a result of Red Hat acquiring Gluster in 2011. Let’s start by installing : GlusterFS apt-get install -y glusterfs-server If you are using another or another distribution, adapt this command to your need. OS Linux GlusterFS Logo I created a machine with no public (the ), this machine will not be able to reach Internet and install unless you setup an Amazon . If you are just making some tests or not familiar with , create a machine with public or create an then assign it to the machine. Notice: IP worker GlusterFS NAT instance AWS IP EIP Create a mount target ( ): brick mkdir -p /glusterfs/bricks/booksfordevops.com : A brick is a directory on an underlying disk . If one of the bricks goes down, there is a hardware failure to make the data available. Notice filesystem Use file to permanently mount the to the new brick: fstab EBS /dev/xvdb /glusterfs/bricks/booksfordevops.com xfs defaults 0 0 Now use in order to apply the modifications that we added to the file. mount /dev/xvdb fstab Under each mount point a directory used for volume: /glusterfs/bricks/booksfordevops.com GlusterFS mkdir /glusterfs/bricks/booksfordevops.com/wordpress Let’s add these lines to the file on each server , we will need this in a following step: /etc/hosts/ 172.31.43.166 node1172.31.14.90 node2 is the and is our . In order to test this configuration, you can execute: from : node1 manager node2 worker ping node2 node1 PING node2 (172.31.14.90) 56(84) bytes of data.64 bytes from node2 (172.31.14.90): icmp_seq=1 ttl=64 time=0.857 ms From the ( ), type the following command to establish cluster nodes trust relationship: manager node1 Gluster gluster peer probe node2 You should have as an output, otherwise check your firewall settings or tail your logs. peer probe: success Now we have a working trusted pool. GlusterFS A storage pool is a trusted network of storage servers ( and in our case). When we started the first server, the storage pool consisted of that server alone. When we added additional storage server to the storage pool (using the command from the storage server that is already trusted), we created a trusted storage pool of 2 servers. GlusterFS node1 node2 node2 probe node1 An Example Of A GlusterFS Architecture Now, from the manager server, we should create a two-way mirror volume that we will call using: booksfordevops-com-wordpress gluster volume create booksfordevops_com-wordpress replica 2 node1:/glusterfs/bricks/booksfordevops.com/wordpress node2:/glusterfs/bricks/booksfordevops.com/wordpress You will get this output: volume create: booksfordevops_com-wordpress: success: please start the volume to access data You can see the volume if you type gluster volume list booksfordevops_com-wordpress Now you should start it using : gluster volume start booksfordevops_com-wordpress If everything is ok, you will get a similar output to this: volume start: booksfordevops_com-wordpress: success Our volume should be healthy but you can check its status using : gluster volume status Status of volume: booksfordevops_com-wordpressGluster process TCP Port RDMA Port Online Pid------------------------------------------------------------------------------Brick node1:/glusterfs/bricks/booksfordevops.com/wordpress 49152 0 Y 1868 Brick node2:/glusterfs/bricks/booksfordevops.com/wordpress 49152 0 Y 17591NFS Server on localhost N/A N/A N N/A Self-heal Daemon on localhost N/A N/A Y 1894 NFS Server on node2 2049 0 Y 17612Self-heal Daemon on node2 N/A N/A Y 17613 Task Status of Volume booksfordevops_com-wordpress------------------------------------------------------------------------------There are no active volume tasks Now that the server is set, we need to setup the client side. Let’s create the directory (in each node) to be used by the client in each node of our cluster: GlusterFS mkdir -p /data/booksfordevops_com-wordpress We need to mount a shared directory on from the and the same directory on from . node2 node1 node1 node2 On , add this line at the end of file: node1 /etc/fstab node2:/booksfordevops_com-wordpress /data/booksfordevops_com-wordpress glusterfs defaults,_netdev 0 0 On , add this line at the end of file: node2 /etc/fstab node1:/booksfordevops_com-wordpress /data/booksfordevops_com-wordpress glusterfs defaults,_netdev 0 0 Then on both hosts, type . mount -a Creating Our Swarm Cluster The next step is to install Docker on both hosts: curl -fsSL https://get.docker.com/ | sh Then initialize the Swarm cluster: docker swarm init Execute the last command on the and you will get a command to execute on the : manager worker docker swarm join \ --token XXXXXX-x-xxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxx \ 172.31.43.116:2377 If everything is ok, the will join the cluster: worker This node joined a swarm as a worker. Deploying Our Application In this tutorial, we want to create a blog, we can host the or the database in our trusted pool but in my specefic case I created an database. Wordpress Mysql MariaDB GlusterFS Aurora We are going to host files in the storage pool we created, that points to . Wordpress /data/booksfordevops_com-wordpress This is the Docker Compose v3 file that we are going to deploy: version: '3'networks: booksfordevops_com-network: services: wordpress: image: wordpress:4.7.3-php7.1-apache ports: - 8000:80 networks: - booksfordevops_com-network volumes: - /data/booksfordevops_com-wordpress:/var/www/html environment: WORDPRESS_DB_HOST: xxxxx.cluster-xxxxx.eu-west-1.rds.amazonaws.com:3306 WORDPRESS_DB_USER: user WORDPRESS_DB_PASSWORD: password WORDPRESS_DB_NAME: db_name WORDPRESS_TABLE_PREFIX: wp_ deploy: mode: replicated replicas: 1 labels: [APP=WORDPRESS] restart_policy: condition: always For security reasons, do not put your file in the same directory as your files in , it will be publicly accessible. Notice: docker-compose.yml Wordpress `/data/booksfordevops_com-wordpress In order to deploy our website, we should execute this command: docker stack deploy --compose-file=docker-compose.yml booksfordevops_com We can use a similar command to the following one in order to deploy the app: Wordpress docker network -d overlay booksfordevops_com-network docker service create --name booksfordevops_com_wordpress \--publish 8000:80 \--mount type=bind,source=/data/wp,target=/var/www/html \-e WORDPRESS_DB_HOST=x.cluster-x.eu-west-1.rds.amazonaws.com:3306 \-e WORDPRESS_DB_USER=user \-e WORDPRESS_DB_PASSWORD=password \-e WORDPRESS_DB_NAME=db_name \-e WORDPRESS_TABLE_PREFIX=wp_ \--replicas 1 \--network booksfordevops_com-network \wordpress:4.7.3-php7.1-apache But putting all together in a Docker Compose v3 file is a more organised way to deploy our app. You may have some premission problems with your fresh installation, you will need to execute these commands: Wordpress cd /data/booksfordevops_com-wordpress chown www-data:www-data -R * find . -type d -exec chmod 755 {} \; find . -type f -exec chmod 644 {} \; In both servers, you can now notice that files are mounted from the service containers to the host volume: Wordpress ls -lrth /data/booksfordevops_com-wordpress -rw-r--r-- 1 www-data www-data 418 Sep 25 2013 index.php-rw-r--r-- 1 www-data www-data 3.3K May 24 2015 wp-cron.php-rw-r--r-- 1 www-data www-data 364 Dec 19 2015 wp-blog-header.php-rw-r--r-- 1 www-data www-data 1.6K Aug 29 2016 wp-comments-post.php-rw-r--r-- 1 www-data www-data 3.0K Aug 31 2016 xmlrpc.php-rw-r--r-- 1 www-data www-data 5.4K Sep 27 21:36 wp-activate.php-rw-r--r-- 1 www-data www-data 4.5K Oct 14 19:39 wp-trackback.php-rw-r--r-- 1 www-data www-data 30K Oct 19 04:47 wp-signup.php-rw-r--r-- 1 www-data www-data 3.3K Oct 25 03:15 wp-load.php-rw-r--r-- 1 www-data www-data 34K Nov 21 02:46 wp-login.php-rw-r--r-- 1 www-data www-data 2.4K Nov 21 02:46 wp-links-opml.php-rw-r--r-- 1 www-data www-data 16K Nov 29 05:39 wp-settings.php-rw-r--r-- 1 www-data www-data 20K Jan 2 18:51 license.txt-rw-r--r-- 1 www-data www-data 7.9K Jan 11 05:15 wp-mail.php-rw-r--r-- 1 www-data www-data 7.3K Jan 11 17:46 readme.htmldrwxr-xr-x 18 www-data www-data 8.0K Mar 6 16:00 wp-includesdrwxr-xr-x 9 www-data www-data 4.0K Mar 6 16:00 wp-admin-rw-r--r-- 1 www-data www-data 2.7K Mar 19 19:41 wp-config-sample.php-rw-r--r-- 1 www-data www-data 3.2K Mar 19 19:41 wp-config.phpdrwxr-xr-x 4 www-data www-data 52 Mar 19 19:51 wp-content If you check the created brick on each server, you will find the same files: ls -lrth /glusterfs/bricks/booksfordevops.com At this step, we have a working installation that you can reach using the address of the and the port . Wordpress IP manager 8000 Adding Traefik: is a reverse proxy and load balancer made to deploy microservices and supports Docker and Docker Swarm (and other backends like / , , , , , and _Rest API_s). Træfɪk HTTP Mesos Marathon Consul Etcd Zookeeper BoltDB Amazon ECS Let’s create a service to run on the manager ( ). The reverse proxy will run on a separate network ( ). Traefik --constraint=node.role==manager --network traefik-net docker network -d overlay traefik-net; docker service create --name traefik \--constraint=node.role==manager \--publish 80:80 \--publish 8080:8080 \--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ --network traefik-net \traefik:v1.1.0-rc1 \--docker \--docker.swarmmode \--docker.domain=traefik \--docker.watch \--web Updating Wordpress Service In order to make our website work with we are going to update its file and add it to the same network . I added also some labels related to like and : Wordpress Traefik docker-compose Traefik traefik-net Traefik port frontend.rule version: '3'networks: traefik-net: external: true booksfordevops_com-network: services: wordpress: image: wordpress:4.7.3-php7.1-apache ports: - 8001:80 networks: - booksfordevops_com-network - traefik-net volumes: - /data/booksfordevops_com-wordpress:/var/www/html environment: WORDPRESS_DB_HOST: xxxx.cluster-xxxxx.eu-west-1.rds.amazonaws.com:3306 WORDPRESS_DB_USER: user WORDPRESS_DB_PASSWORD: password WORDPRESS_DB_NAME: db_name WORDPRESS_TABLE_PREFIX: wp_ deploy: mode: replicated replicas: 2 labels: APP: WORDPRESS traefik.port: 80 traefik.frontend.rule: "Host:booksfordevops.com,www.booksfordevop.com" restart_policy: condition: on-failure Update the deployment using docker stack deploy --compose-file=docker-compose.yml booksfordevops_com You can check if the configured domain is accessible using a simple , in my case: curl curl -H Host:booksfordevops.com http://127.0.0.1 You can also go to the health dashboard in order to see things like the response time and the status codes of our application. What We Learned We saw how to build a highly available website, where storage and computing are distributed into two different regions. Wordpress Within each machine we can scale to more than one container and have another level of resilience. EC2 Wordpress Our reverse proxy can check the health of each container and manage to redirect traffic to the working ones. We used modern tools and technologies like: Amazon RDS Amazon EC2 GlusterFS Docker Docker Swarm Traefik Our website is working, you can subscribe and wait for release. Books For DevOps Connect Deeper This article is part of . Painless Docker Book: Unlock The Power Of Docker & Its Ecosystem is a practical guide to master and based . Painless Docker Docker its ecosystem on real world examples Painless Docker tends to be a complete and detailed guide to create, deploy, optimize, secure, trace, debug, log, orchestrate & monitor Docker and Docker clusters. Through this book you will learn how to use Docker in development and production environments and the DevOps pipeline between them in order to build a modern microservices applications. If you resonated with this article, please subscribe to : . DevOpsLinks An Online Community Of Diverse & Passionate DevOps, SysAdmins & Developers From All Over The World You can find me on , or my and you can also check my books: & . Twitter Clarity blog SaltStack For DevOps The Jumpstart Up If you liked this post, please recommend and share it to your followers.