|
dave spink toolset |
|
DOCKER: |
|||
COMMANDS | OVERVIEW | INSTALL | EXAMPLES |
COMPOSE | SCALING | SWARM | STACK |
THE PROJECTThe HPE Deep Learning Benchmark Suite (DLBS) uses Docker. When we implemented DLBS at Verizon (VMG) they had a whole series of Docker questions e.g. how does docker work, how do you access a running docker container etc. Hence, we needed to learn docker to answer those questions…. | |
| |
COMMANDS | |
Docker Commands | |
docker info | ;lots of good info |
docker ps | ;shows all actively running containers |
docker ps -a | ;see all containers that have been run or running |
docker ps --filter status=exited | ;see containers that are no longer running |
docker rm e2e1eb939c72 | ;delete a specific container |
docker container prune | ;delete all containers that have run |
docker images | ;see list of repository images on system |
docker image rmi mysql | ;delete old images |
docker run --help | ;see help files |
docker build . -t webapp:latest | ;build an image |
docker run --name test1 hello-world | ;creates a container instance of the image and runs it |
docker run -d -p 80:80 --name mytest1 --rm webapp | ;detach terminal, expose port 80, delete container instance when its stopped running |
docker run -it --rm ubuntu:latest /bin/bash | ;access the shell of an image |
docker exec -it mytest1 /bin/bash | ;access the shell of a running container |
docker stop mytest1 | ;stop a running container |
docker start mytest1 | ;re-start the container you just stopped |
docker stop $(docker ps -q) | ;stop all running containers |
docker tag webapp spinkd/webapp | ;duplicate an image with a new name |
docker run -it --rm php:latest /bin/bash | ;obtain a php container and open a bash shell; you can run php -v to see version |
docker logs -f --tail 10 mytest1 | ;see docker console logs of a container; either running or not running |
docker run -d -P httpd | ;detach terminal and expose the random port |
curl -I "http://localhost:32776" | ;health check |
docker run -it --link "httpd:web" ubuntu /bin/bash | ;link container httpd and ubuntu, with an alias name web |
docker inspect mytest1 | ;see details (network, performance, configs) of a running container |
docker rm $(docker ps --filter status=exited -q) | ;clean-up those containers that have status exited |
docker network ls | ;list all current running networks |
docker network prune | ;cleans up un-used networks |
docker login docker.io | ;login to docker repository, the default registry is docker.io |
docker push spinkd/webapp:latest | ;push image up to your repository (must login into repo first) |
Docker Compose | |
docker-compose up -d | ;run docker compose, requires a yaml file |
docker-compose stop | ;stop containers listed in the yaml file |
docker-compose down | ;stop and remove the containers in the yaml file |
docker-compose pull | ;pre pull required images |
docker-compose restart | ;will restart all the instances |
docker-compose pause | ;this is pausing the instances, basically takes it offline and hangs the processes |
docker-compose unpause | ;this un-pauses |
docker-compose top | ;to see process ID's are active |
docker-compose logs | ;to see console logs |
Docker Swarm | |
docker swarm init --advertise-addr 10.0.2.15 | ;initialize swarm on your manager node |
docker info | ;lots of good info (see Swarm info / status) |
docker node ls | ;see list of cluster nodes (managers and workers) |
docker service create -p 80:80 --name webservice --replicas 3 httpd | ;launch swarm service |
docker service ps webservice | ;see containers running in the service |
docker service scale webservice=5 | ;scale up or down services |
docker node promote workernode1 | ;promote a worker node to take over manager if needed |
docker node demote workernode1 | ;demote a worker node |
docker swarm leave | ;leave a swarm |
docker inspect workernode2 | ;see details of the worker node |
docker service update -h | ;help |
Docker Stack: | |
docker stack deploy -c docker-stackdeploy.yaml mystack | |
docker service ps mystack_apache_httpd | |
docker service update --publish-add 80:80 mystack_apache_httpd | |
docker service logs mystack_apache_httpd | |
docker stack ps mystack | |
| |
OVERVIEW
Containers are isolated, but share an OS and where appropriate share bins and libraries. They are not a new approach i.e. Solaris had zones, BSB had jails however Google donated "cgroups" into the Linux kernel which became a critical component of LXC (LinuX Containers). Docker has made containers easy to use. Note: containers do not change any of the fundamental underlying storage limitations or features.
Terminology:
Iamges:
Dockerfile:
$ vi dockerfile FROM ubuntu:latest CMD echo "Hello, this is the first container I have built." Docker Process:
Docker Compose:
Docker Swarm:
Docker Stack Deploy:
Uploading your builds (images) to Docker Hub:
$ docker login docker.io Username: spinkd Password: $ docker push spinkd/webapp:latest The push refers to repository [docker.io/spinkd/webapp] INSTALLhttps://docs.docker.com/install/linux/docker-ce/centos/ Remove older versions: $ sudo yum remove docker-ce $ sudo rm -rf /var/lib/docker Install required packages: $ sudo yum install -y yum-utils device-mapper-persistent-data lvm2 Add a stable repository: $ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo Install Docker CE (community edition) $ sudo yum install docker-ce $ sudo yum install docker-ce docker-ce-cli containerd.io Post install steps: $ sudo systemctl start docker $ sudo docker run hello-world $ sudo usermod -aG docker dave $ sudo systemctl enable docker $ sudo chkconfig docker on Logoff / Logon Verify that Docker can resolve external IP addresses by trying to pull an image: $ docker pull hello-world ;pulling an image is akin to a Git repository $ docker run hello-world ;creates and runs a container instance from the hello-world image What happens when you run $ docker run -i -t ubuntu /bin/bash
Install Docker-Compose. Check you have the latest version https://docs.docker.com/compose/install/ $ sudo curl -L https://github.com/docker/compose/releases/download/1.24.0-rc1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose $ docker-compose -v e5c864f50b6e49c3b5cad019baadd713 EXAMPLESThe following docker examples are from "Docker from A to Z; Swarm + Jenkins" by James Kayes-Smith on Udemy. I highly recommended his course. A basic container example: Create a docker file: $ vi dockerfile FROM ubuntu:latest CMD echo "Hello, this is the first container I have built." Build the docker image, the dot is the path to the docker file, and -t is the image name to create: $ docker build . -t daves-test Run the container: $ docker run daves-test Hello, this is the first container I have built. A basic web app: Create a HTML file: $ vi webapp.html <html> <body> <h1>Hello world!</h1> </body> </html> Specify the root directory for your web server: $ vi nginx.conf server { root /www; } Create a docker file i.e. use the open source image (nginx) and "add" your commands: $ vi Dockerfile FROM nginx:latest ADD webapp.html /www/ ADD nginx.conf /etc/nginx/conf.d/default.conf Build the docker image: $ docker build . -t webapp:latest Sending build context to Docker daemon 4.096kB Step 1/3 : FROM nginx:latest ---> 56ca8c4670fa80 Step 2/3 : ADD webapp.html /www/ ---> Using cache ---> 7260f0c05813 Step 3/3 : ADD nginx.conf /etc/nginx/conf.d/default.conf ---> Using cac ---> e6d0b965ec3b Successfully built e6d0b965ec3b Successfully tagged webapp:latest List the docker images: $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE webapp latest e6d0b965ec3b 3 hours ago 109MB Run a container instance from the "webapp" image. Expose port 80, detach terminal, and delete the container instance once it's stopped running: $ docker run -d -p 80:80 --name mytest1 --rm webapp
Run another container instance exposing a different port number: $ docker run -d -p 84:80 --name mytest2 --rm webapp
Access the shell of a running container: $ docker exec -it mytest1 /bin/bash root@79d09948fc9d:/# ls /www webapp.html Show the exposed ports a container: $ docker port mytest2 80/tcp -> 0.0.0.0:84 See what containers are running: $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 96fb021c25b6 webapp "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:85->84/tcp mytest2 c248a64c9a11 webapp "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:85->80/tcp mytest1 Stop the running containers: $ docker stop mytest1 $ docker stop mytest2 Install Software via a Dockerfile: The "run" command is saying run this command on the base image and save it into the new image. $ vi dockerfile FROM ubuntu:latest RUN apt-get update && apt-get install -y --no-install-recommends vim && apt-get clean Build your image: $ docker build . -t ubuntu-vim Run a container and verify your software is installed: $ docker run -it --rm ubuntu-vim /bin/bash root@da908cdb6de4:/# which vim /usr/bin/vim root@da908cdb6de4:/# vim Using Docker Health Check to monitor an application: Create a docker file: $ vi dockerfile FROM httpd:latest RUN apt-get update && apt-get install -y --no-install-recommends curl && apt-get clean EXPOSE 80 HEALTHCHECK --interval=15s --retries=5 --timeout=30s --start-period=30s CMD curl -I -f "http://localhost:80" || exit 1 Build the image: $ docker build . -t httpd-health Run a container from the image: $ docker run -d -P --name httpd-hc httpd-health:latest See the running container: $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3260a02199cc httpd-health "httpd-foreground" 8 seconds ago Up 7 seconds (health: starting) 0.0.0.0:32777->80/tcp httpd-hc $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3260a02199cc httpd-health "httpd-foreground" 5 minutes ago Up 5 minutes (healthy) 0.0.0.0:32777->80/tcp httpd-hc View the container console logs $ docker logs -f httpd-hc 127.0.0.1 - - [21/Dec/2018:17:30:07 +0000] "HEAD / HTTP/1.1" 200 - 127.0.0.1 - - [21/Dec/2018:17:36:13 +0000] "HEAD / HTTP/1.1" 200 - 172.17.0.1 - - [21/Dec/2018:17:36:16 +0000] "GET / HTTP/1.1" 304 - 172.17.0.1 - - [21/Dec/2018:17:36:26 +0000] "GET / HTTP/1.1" 304 - 127.0.0.1 - - [21/Dec/2018:17:36:28 +0000] "HEAD / HTTP/1.1" 200 Stop the container: $ docker stop httpd-hc Linking Containers "mysql" and "adminer": Run an instance of mysql and set an environment variable. Notice how we don't expose any ports on this container: $ docker run --name mysql -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7 Unable to find image 'mysql:5.7' locally 5.7: Pulling from library/mysql 27833a3ba0a5: Already exists 864c283b3c4b: Pull complete … Status: Downloaded newer image for mysql:5.7 Link the adminer container: $ docker run --link "mysql:db" -p 8080:8080 adminer Unable to find image 'mysql:5.7' locally 5.7: Pulling from library/mysql 27833a3ba0a5: Already exists 864c283b3c4b: Pull complete … Status: Downloaded newer image for mysql:5.7 Access adminer via browser and login:
Stop the container: $ docker stop adminer $ docker stop mysql COMPOSEDocker Compose
Use Docker Compose to link containers "mysql" and "adminer": Create the YAML file and include a persistent data volume: $ vi docker-compose-db.yaml version: '3.1' services: db: image: mysql:5.7 restart: always environment: MYSQL_ROOT_PASSWORD: password volumes: - dbdata:/var/lib/mysql adminer: image: adminer:latest restart: always ports: - 8080:8080 volumes: dbdata: driver: local Run docker compose: $ docker-compose -f docker-compose-db.yaml up -d Creating dockerstuff_adminer_1 ... done Creating dockerstuff_db_1 ... done See the running container: $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da0dc2067e76 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up 58 seconds 3306/tcp, 33060/tcp docker_db_1 5fdf1482cc10 adminer:latest "entrypoint.sh docke…" About a minute ago Up 58 seconds 0.0.0.0:8080->8080/tcp docker_adminer_1 Access adminer via browser and login:
Create a "test" database and "test" table:
Stop containers using docker compose: $ docker-compose -f docker-compose-db.yaml down Stopping dockerstuff_adminer_1 ... done Stopping dockerstuff_db_1 ... done Removing dockerstuff_adminer_1 ... done Removing dockerstuff_db_1 ... done Removing network dockerstuff_default See the docker volume still exists: $ docker volume ls DRIVER VOLUME NAME local dockerstuff_dbdata See the volume contents via sudo and notice the "test" table created: $ sudo ls /var/lib/docker/volumes/dockerstuff_dbdata/_data auto.cnf ca.pem client-key.pem ibdata1 ib_logfile1 performance_schema public_key.pem server-key.pem TEST Start the instances again: $ docker-compose -f docker-compose-db.yaml up -d Creating network "dockerstuff_default" with the default driver Creating dockerstuff_db_1 ... done Creating dockerstuff_adminer_1 ... done Log back in and see the "test" DB we created has persisted:
SCALINGThere is a simple way within docker to scale an application, however the service container must be stateless e.g. you couldn't say have an authentication service running in one container maintaining state within that container, as if the app container issued another request and was load balanced over to another server container it wouldn't know the login state and therefore request another login.
Create a docker compose file with a httpd service: $ cat docker-compose-httpd.yaml version: '3.1' services: web: image: httpd:latest restart: always Startup a single instance: $ docker-compose -p scaletest -f docker-compose-httpd.yaml up -d Starting scaletest_web_1 ... done $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d947a5627c15 httpd:latest "httpd-foreground" About a minute ago Up 23 seconds 80/tcp scaletest_web_1 Scale out the instances for a total of 3 instances: $ docker-compose -p scaletest -f docker-compose-httpd.yaml up -d --scale web=3 Starting scaletest_web_1 ... done Creating scaletest_web_2 ... done Creating scaletest_web_3 ... done $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 10ee4aeefcb8 httpd:latest "httpd-foreground" 3 seconds ago Up 1 second 80/tcp scaletest_web_2 07470ec372d9 httpd:latest "httpd-foreground" 3 seconds ago Up 1 second 80/tcp scaletest_web_3 d947a5627c15 httpd:latest "httpd-foreground" About a minute ago Up 36 seconds 80/tcp scaletest_web_1 SWARMDocker Swarm
Pre-requisites 3 VMs:
Enable ports on the firewall: $ firewall-cmd --permanent --add-port=2376/tcp $ firewall-cmd --permanent --add-port=2377/tcp $ firewall-cmd --permanent --add-port=7946/tcp $ firewall-cmd --permanent --add-port=7946/udp $ firewall-cmd --permanent --add-port=4789/udp $ firewall-cmd --permanent --add-port=80/tcp $ firewall-cmd --reload $ systemctl restart docker Launch the Swarm or Cluster: $ docker swarm init --advertise-addr 10.0.2.15 Swarm initialized: current node (cthhb9ughwvwm2b8m6krtnzfi) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-3jn9z600gwpm9ot8fgiq8kufgow4chd1mni07svwe9i1o53wim-8hzm8brhnv4ruzke2xgjc6c79 10.0.2.15:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. Verify the manager status: $ docker info $ docker node ls Add worker nodes: [workernode1] $ docker swarm join --token SWMTKN-1-3jn9z600gwpm9ot8fgiq8kufgow4chd1mni07svwe9i1o53wim-8hzm8brhnv4ruzke2xgjc6c79 10.0.2.15:2377 [workernode2] $ docker swarm join --token SWMTKN-1-3jn9z600gwpm9ot8fgiq8kufgow4chd1mni07svwe9i1o53wim-8hzm8brhnv4ruzke2xgjc6c79 10.0.2.15:2377 See the list of node members: $ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION cthhb9ughwvwm2b8m6krtnzfi * dkmanager Ready Active Leader 18.09.3 01xnssr9bs9z74bxssm2u2y25 workernode1 Ready Active 18.09.3 rdezth7cbxmh5jlpgg8pa29i9 workernode2 Ready Active 18.09.3 Launch the service in Swarm mode: $ docker service create -p 80:80 --name webservice --replicas 3 httpd $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS z96orvprn5s1 webservice replicated 3/3 httpd:latest *:80->80/tcp Log into the web page from any node: http://workernode1/ http://workernode2/ http://dkmanager/ Testing Container Self-Healing: workernode2 ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a02f005e5f5a httpd:latest "httpd-foreground" 7 minutes ago Up 7 minutes 80/tcp webservice.2.x1ci56r3a1ue9in51ryu8zsvc Remove container on worker node 2: workernode2 ~]$ docker rm a02f005e5f5a -f a02f005e5f5a Check whether a new container is deployed from the Manager node: dkmanager ~]$ docker service ps webservice ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR kdteg161kjda webservice.1 httpd:latest workernode1 Running Running 10 minutes ago xs29qsbumj8q webservice.2 httpd:latest workernode2 Running Running 55 seconds ago x1ci56r3a1ue \_ webservice.2 httpd:latest workernode2 Shutdown Failed about a minute ago "task: non-zero exit (137)" v5g3gowwfitr webservice.3 httpd:latest dkmanager Running Running 10 minutes ago Scaling up the containers: dkmanager ~]$ docker service scale webservice=5 webservice scaled to 5 overall progress: 5 out of 5 tasks 1/5: running [==================================================>] 2/5: running [==================================================>] 3/5: running [==================================================>] 4/5: running [==================================================>] 5/5: running [==================================================>] verify: Service converged $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS z96orvprn5s1 webservice replicated 5/5 httpd:latest *:80->80/tcp $ docker service ps webservice ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR kdteg161kjda webservice.1 httpd:latest workernode1 Running Running 15 minutes ago xs29qsbumj8q webservice.2 httpd:latest workernode2 Running Running 6 minutes ago x1ci56r3a1ue \_ webservice.2 httpd:latest workernode2 Shutdown Failed 6 minutes ago "task: non-zero exit (137)" v5g3gowwfitr webservice.3 httpd:latest dkmanager Running Running 15 minutes ago 2brymttzq6xy webservice.4 httpd:latest workernode1 Running Running about a minute ago ofkjbi0hj1wr webservice.5 httpd:latest dkmanager Running Running about a minute ago Scale down the containers: dkmanager ~]$ docker service scale webservice=2 webservice scaled to 2 overall progress: 2 out of 2 tasks 1/2: running [==================================================>] 2/2: running [==================================================>] verify: Service converged $ docker service ls ID NAME MODE REPLICAS IMAGE PORTS z96orvprn5s1 webservice replicated 2/2 httpd:latest *:80->80/tcp dkmanager ~]$ docker service ps webservice ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR kdteg161kjda webservice.1 httpd:latest workernode1 Running Running 19 minutes ago xs29qsbumj8q webservice.2 httpd:latest workernode2 Running Running 10 minutes ago x1ci56r3a1ue \_ webservice.2 httpd:latest workernode2 Shutdown Failed 10 minutes ago "task: non-zero exit (137)" Promote a worker node so that they can take over as a manager if needed: dkmanager ~]$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION cthhb9ughwvwm2b8m6krtnzfi * dkmanager Ready Active Leader 18.09.3 01xnssr9bs9z74bxssm2u2y25 workernode1 Ready Active 18.09.3 rdezth7cbxmh5jlpgg8pa29i9 workernode2 Ready Active 18.09.3 dkmanager ~]$ docker node promote workernode1 Node workernode1 promoted to a manager in the swarm. dkmanager ~]$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION cthhb9ughwvwm2b8m6krtnzfi * dkmanager Ready Active Leader 18.09.3 01xnssr9bs9z74bxssm2u2y25 workernode1 Ready Active Reachable 18.09.3 rdezth7cbxmh5jlpgg8pa29i9 workernode2 Ready Active 18.09.3 Constrain service to run on one node (e.g. if there was a specific volume they needed): dkmanager ~]$ docker service ps webservice ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION qodbwhfemxzh webservice.1 nginx:latest workernode1 Running Running about an hour ago g0tp3g6hi4fj webservice.2 nginx:latest workernode2 Running Running about an hour ago m00aojvje9cm webservice.4 nginx:latest dkmanager Running Running about an hour ago dkmanager ~]$ docker service update --constraint-add "node.hostname==workernode1" webservice webservice overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged dkmanager ~]$ docker service ps webservice ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR qodbwhfemxzh webservice.1 nginx:latest workernode1 Running Running about an hour ago nvy71utti8eu webservice.2 nginx:latest workernode1 Running Running 13 seconds ago g0tp3g6hi4fj \_ webservice.2 nginx:latest workernode2 Shutdown Shutdown 14 seconds ago k1eh2xgio1pe webservice.4 nginx:latest workernode1 Running Running 9 seconds ago m00aojvje9cm \_ webservice.4 nginx:latest dkmanager Shutdown Shutdown 10 seconds ago Remove the service: dkmanager ~]$ docker service rm webservice webservice Docker Swarm Load Balancing: Load Balancing - See below for trying to access the nginx service on the worker server that is running a MySql container. The swarm service will automatically proxy the request over to the container that is running on the other node. Note: In real production you would have a HA proxy out front that points to all three servers. Let's prove this out - see below.
Check docker service is running: dkmanager ~]$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION yp4kb1p66bquae8x0vsjokhvx * dkmanager Ready Active Leader 18.09.3 0uez56kuhaa6dgv8wms6jkmel workernode1 Ready Active 18.09.3 t07id57u3n6y248rliobvjwx2 workernode2 Ready Active 18.09.3 Create just one container: dkmanager ~]$ docker service create -p 80:80 --name webservice --replicas 1 nginx Validate the service is running: dkmanager ~]$ docker service ps webservice ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS qodbwhfemxzh webservice.1 nginx:latest workernode1 Running Running 5 minutes ago Validate there is no containers running on the other servers: workernode2 ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dkmanager ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES STACKDocker Stack Deploy
Confirm you have a Swarm service running: dkmanager dockerstuff]$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION yp4kb1p66bquae8x0vsjokhvx * dkmanager Ready Active Leader 18.09.3 0uez56kuhaa6dgv8wms6jkmel workernode1 Ready Active 18.09.3 t07id57u3n6y248rliobvjwx2 workernode2 Ready Active 18.09.3 Create a compose yaml file: services: apache_httpd: image: httpd:latest deploy: mode: replicated replicas: 2 labels: com.docker.descr: "contact dave" restart_policy: condition: any delay: 5s max_attempts: 3 window: 120s placement: constraints: - node.role == worker resources: limits: memory: 50M reservations: cpus: '0.10' update_config: parallelism: 1 delay: 10s monitor: 5s Deploy docker stack: dkmanager dockerstuff]$ docker stack deploy -c docker-stackdeploy.yaml mystack Creating network mystack_default Creating service mystack_apache_httpd Verify service is running. Note, we didn't have an exposed port!: dkmanager dockerstuff]$ docker stack ls NAME SERVICES ORCHESTRATOR mystack 1 Swarm dkmanager dockerstuff]$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS ksebzpin6ily mystack_apache_httpd replicated 2/2 httpd:latest dkmanager dockerstuff]$ docker service ps mystack_apache_httpd ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 8qrrmo16u7wo mystack_apache_httpd.1 httpd:latest workernode2 Running Running 2 minutes ago rz1e0978lgci mystack_apache_httpd.2 httpd:latest workernode1 Running Running 2 minutes a Perform a live update to the service, adding the exposed port that we forgot to include the yaml file: dkmanager dockerstuff]$ docker service update --publish-add 80:80 mystack_apache_httpd mystack_apache_httpd overall progress: 2 out of 2 tasks 1/2: running [==================================================>] 2/2: running [==================================================>] verify: Service converged dkmanager dockerstuff]$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS ksebzpin6ily mystack_apache_httpd replicated 2/2 httpd:latest *:80->80/tcp dkmanager dockerstuff]$ curl workernode1 <html><body><h1>It works!</h1></body></html> |