{"id":18358698,"url":"https://github.com/david-yu/cisco-docker-mta-workshop","last_synced_at":"2026-01-22T14:37:22.881Z","repository":{"id":86139901,"uuid":"100068490","full_name":"david-yu/cisco-docker-mta-workshop","owner":"david-yu","description":"Cisco Docker MTA Workshop ","archived":false,"fork":false,"pushed_at":"2017-09-06T00:26:38.000Z","size":620,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T03:07:43.944Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/david-yu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-11T20:37:58.000Z","updated_at":"2018-03-01T14:46:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"3019a803-70f5-4892-b57e-4e97a3f3275f","html_url":"https://github.com/david-yu/cisco-docker-mta-workshop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/david-yu/cisco-docker-mta-workshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/david-yu%2Fcisco-docker-mta-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/david-yu%2Fcisco-docker-mta-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/david-yu%2Fcisco-docker-mta-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/david-yu%2Fcisco-docker-mta-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/david-yu","download_url":"https://codeload.github.com/david-yu/cisco-docker-mta-workshop/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/david-yu%2Fcisco-docker-mta-workshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28664656,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T14:01:31.714Z","status":"ssl_error","status_checked_at":"2026-01-22T13:59:23.143Z","response_time":144,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T22:19:13.183Z","updated_at":"2026-01-22T14:37:22.867Z","avatar_url":"https://github.com/david-yu.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Deploying Multi-OS applications to Docker EE\nDocker EE 17.06 is the first Containers-as-a-Service platform to offer production-level support for the integrated management and security of Linux AND Windows Server Containers.\n\nIn this lab we'll build a Docker EE cluster comprised of Windows and Linux nodes. Then we'll deploy both a Linux and Windows web app, as well as a multi-service application that includes both Windows and Linux components.\n\n\u003e **Difficulty**: Intermediate (assumes basic familiarity with Docker)\n\n\u003e **Time**: Approximately 60 minutes\n\n\u003e **Tasks:**\n\u003e\n\u003e * [Prerequisites](#prerequisites)\n\u003e * [Task 1: Build a Docker EE Cluster](#task1)\n\u003e   * [Task 1.1: Install the UCP manager](#task1.1)\n\u003e   * [Task 1.2: Install a Linux worker node](#task1.2)\n\u003e   * [Task 1.3: Install a Windows worker node](#task1.3)\n\u003e   * [Task 1.4: Install DTR and Create Two Repositories](#task1.4)\n\u003e   * [Task 1.5: Install Self Signed Certs on All Nodes](#task1.5)\n\u003e * [Task 2: Deploy a Linux Web App](#task2)\n\u003e   * [Task 2.1: Clone the Demo Repo](#task2.1)\n\u003e   * [Task 2.2: Build and Push the Linux Web App Image](#task2.2)\n\u003e   * [Task 2.3: Deploy the Web App using UCP](#task2.3)\n\u003e * [Task 3: Deploy a Windows Web App](#task3)\n\u003e   * [Task 3.1: Create the Dockerfile with Image2Docker](#task3.1)\n\u003e   * [Task 3.2: Build and Push Your Image to Docker Trusted Registry](#task3.2)\n\u003e   * [Task 3.3: Deploy the Windows Web App](#task3.3)\n\n## Document Conventions\n\n- When you encounter a phrase between `\u003c` and `\u003e` you are meant to substitue a different value.\n\tFor example: if you see `\u003clinux vm name\u003e` you would actually type something like `pod-1-lin01`\n\n- When you see the Linux Penguin, all of the following instructions should be executed in one of your Linux VMs.\n\n\t![](./images/linux75.png)\n\t\n- When you see the Windows Flag, all of the subsequent instructions should be completed in your Windows VM.\n\n\t![](./images/windows75.png)\n\t\n### Virtual Machine Naming Conventions\nYour VMs are named in the following convention pod-X-[OS]YY.csc.pittsburgh.cisco.com\nWhere X is the pod number [OS] is the Operating System type and YY is the Node number.  \n\n\u003e For example: `pod-3-lin02` or `pod-3-win01`\n\n### Virtual Machine Roles\nThis lab uses a total of five virtual machines\n\nThe Docker EE cluster you will be building will be comprised of five nodes - 4 Linux nodes running Centos7 and 1 Windows node running Server 2016.\n\n![](./images/vm_roles.png)\n\n## \u003ca name=\"prerequisites\"\u003e\u003c/a\u003ePrerequisites\n\nYou will be provided a set of five virtual machines (four Linux and 1 Windows), which we will be configuring with Docker\t. You do not need Docker running on your laptop, but you will need a Remote Desktop client to connect to the Windows VM, and an SSH client to connect into the Linux one.\n### 1. RDP Client\n\n- Windows - use the built-in Remote Desktop Connection app.\n- Mac - install [Microsoft Remote Desktop](https://itunes.apple.com/us/app/microsoft-remote-desktop/id715768417?mt=12) from the app store.\n- Linux - install [Remmina](http://www.remmina.org/wp/), or any RDP client you prefer.\n\n### 2. SSH Client\n\n- Windows - [Download Putty](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)\n- Linux - Use the built in SSH client\n- Mac - Use the built in SSH client\n\n\u003e **Note**: When you connect to the Windows VM, if you are prompted to run Windows Update, you should cancel out. The labs have been tested with the existing VM state and any changes may cause problems.\n\n## \u003ca name=\"task1\"\u003e\u003c/a\u003eTask 1: Build a Docker EE Cluster\n\nIn this first step we're going to install Docker Universal Control Plane (UCP) and Docker Trusted Registry. UCP is a web-based control plane for Docker containers that can deploy and manage Docker-based applications across Windows and Linux nodes.  Docker Trusted Registry is a private registry server for storing your Docker images.\n\n### \u003ca name=\"task1.1\"\u003e\u003c/a\u003eTask 1.1: Install the UCP manager\n\n\u003e **Note**: In the current version of UCP manager nodes must be Linux. Worker nodes can be Windows or Linux\n\n![](./images/linux75.png)\n\n1. Either in a terminal window (Mac or Linux) or using Putty (Windows) SSH into Linux node **01** using the IP Address. The IP Address can be found on your lab information paper.  The username is `docker` and the password is `Docker2017`\n\n\t`ssh docker@\u003cpod-X-lin01\u003e`\n\nStart the UCP installation on the current node, and make it your UCP manager.\n\nRun the following command to pull the image and install UCP.\n\n```\ndocker container run --rm -it --name ucp \\\n-v /var/run/docker.sock:/var/run/docker.sock \\\ndocker/ucp:2.2.2 install \\\n--admin-username docker \\\n--admin-password Docker2017 \\\n--host-address \u003cpod-X-lin01 Ip Address\u003e \\\n--interactive\n```\n\nYou will see output similar to the following:\n\n```\nUnable to find image 'docker/ucp:latest' locally\nlatest: Pulling from docker/ucp\n88286f41530e: Pull complete \n054affee0b99: Pull complete \n1247b4599b73: Pull complete \nDigest: sha256:fb8935c92876a5255bd5ab26f2a9910918490b7eb8457323d46e416ac2b4d226\nStatus: Downloaded newer image for docker/ucp:latest\nINFO[0000] Verifying your system is compatible with UCP 2.2.2 (94d1abdf3) \nINFO[0000] Your engine version 17.06.1-ee-2, build 8e43158 (3.10.0-514.26.2.el7.x86_64) is compatible \nWARN[0000] Your system uses devicemapper.  We can not accurately detect available storage space.  Please make sure you have at least 3.00 GB available in /var/lib/docker\n```\n\nThis will take a few minutes while the images are downloaded and deployed.\nWhen prompted for something similar to the below press enter.\n\n```\nYou may enter additional aliases (SANs) now or press enter to proceed with the above list.\nAdditional aliases:\n```\n\n1. Download the [license file](https://drive.google.com/file/d/0ByQd4O58ibOEazFVRUJYNDYxMjg/view?usp=sharing) to your local laptop.\n\n2. Open a web browser and type in the ip address of `pod-X-lin01` in the address bar.  Ignore any certificate warnings and continue.\n\n\t![](./images/ucp_login.png)\n\n3. Login to UCP using the credentials we defined during the installation (docker/Docker2017).\n\n\t![](./images/ucp_license.png)\n\t\n4. Click `Upload License`, navigate to your license location, and double-click the license file\n\nCongratulations, you have installed the UCP manager node.\n\n### \u003ca name=\"task1.2\"\u003e\u003c/a\u003eTask 1.2: Install a Linux worker nodes\n\nNow that we have a manager node, we'll add the Linux worker nodes to our cluster. Worker nodes are the servers that actually run our Docker-based applications.\n\n1. From the main UCP dashboard click `Nodes` and then `Add Nodes`.\n2. Copy the text in the box to your clipboard.\n\t\u003e **Note** There is an icon in the upper right corner of the box that you can click to copy the text to your clipboard\n\t![](./images/add_node.png)\n3.  SSH into the remaining Linux nodes (pod-X-lin02 - pod-X-lin04)\n\t`ssh docker@\u003clinux node IP Address\u003e`\n4. Paste the text from Step 2 at the command prompt, and press enter.\n\n\tYou should see the message `This node joined a swarm as a worker.` indicating you've successfully joined the node to the cluster.\n\n5. Switch back to the UCP console in your web browser and click the `x` in the upper right corner to close the `Add Node` window\n\n6. You should be taken to the `Nodes` screen will will see 4 nodes listed at the bottom of your screen. Your  lin01 node is the manager, and the lin02-04 node are your workers.\n\nCongratulations on adding your worker nodes.\n\nIn the next step we'll install and configure a Windows worker node.\n\n### \u003ca name=\"task1.3\"\u003e\u003c/a\u003eTask 1.3: Install a Windows worker node\n\n![](./images/windows75.png)\n\nLet's add our 5th node to the cluster, a Windows Server 2016 worker node. The process is basically exactly the same as it was for Linux\n\n1. From the Nodes screen, click the blue `Add node` button in the middle of the screen on the right hand side.\n\n\u003e **Note**: You may notice that there is a UI component to select `Linux` or `Windows`. The lab VMs already have the Windows components pre installed, so you do NOT need to select `Windows`. Just leave the selecton on `Linux` and move on to step 2\n\n2. Copy the text from the dark box shown on the `Add Node` screen.\n\n\t\u003e **Note** There is an icon in the upper right corner of the box that you can click to copy the text to your clipboard\n\t\n\t![](./images/add_node.png)\n\n3. Use RDP to log in to `pod-X-win05`.\n\n4. From the Start menu open a Powershell window (Start \u003e Powershell (right click and run as administrator)\n\n4. Paste the text from Step 2 at the command prompt, and press enter.\n\n\tYou should see the message `This node joined a swarm as a worker.` indicating you've successfully joined the node to the cluster.\n\n5. Switch back to your web browser and click the `x` in the upper right corner to close the `Add Node` window\n\n6. You should be taken to the `Nodes` screen will will see 5 nodes listed at the bottom of your screen. Your Linux nodes and Windows nodes.\n\nCongratulations on building your UCP cluster. Next up we'll install and configure DTR.\n\n### \u003ca name=\"task1.4\"\u003e\u003c/a\u003eTask 1.4: Install DTR and Create Two Repositories\n\n![](./images/linux75.png)\n\nLike UCP, DTR uses a single Docker container to bootstrap the install process. In the first step we'll kick off that container to install DTR, and then we'll create two repositories that we'll use later for our Tweet apps we're going to deploy.\n\n1.  Run the bootstrap to deploy DTR.\n\tYou will need to supply three inputs:\n\t\n\t* **--dtr-external URL**: `\u003cpod-X-lin01 IP Address\u003e`\n\t* **--ucp-node**: The hostname of `lin02` (For example: pod-X-lin02)\n\t* **--ucp-url**: The IP address of the UCP Manager (pod-X-lin01)\n\t\n\t```\n\tdocker run -it --rm docker/dtr install \\\n\t--dtr-external-url \u003cpod-X-lin02 IP Address \\\n\t--ucp-node \u003cpod-X-lin02\u003e \\\n\t--ucp-username docker \\\n\t--ucp-password Docker2017 \\\n\t--ucp-url \u003cpod-X-lin01 IP Address\u003e \\\n\t--ucp-insecure-tls\n\t```\n\n\tYou will see a lot of output scroll by while DTR installs finishing with:\n\n\t```\n\t\u003coutput deleted\u003e\n\tINFO[0160] Successfully registered dtr with UCP\n\tINFO[0161] Establishing connection with Rethinkdb\n\tINFO[0162] Background tag migration started\n\tINFO[0162] Installation is complete\n\tINFO[0162] Replica ID is set to: 8ec3809e352e\n\tINFO[0162] You can use flag '--existing-replica-id 8ec3809e352e' when joining other replicas to your Docker Trusted Registry Cluster\n\tINFO[0185] finished reading output\n\t```\n5. Point your web browser to `https://\u003cpod-X-lin02 IP Address\u003e` and log in with the username `docker` and the password `Docker2017`.\n\n\t\u003e **Note**: You need to use `https:` NOT `http`\n\n\t\u003e **Note**: Because UCP uses self-signed SSL certs, your web browser may warn you that your connection is not secure. You will need to click through that warning. An example from Chrome is shown below.\n\nNow that DTR is installed, let's go ahead and create a couple of repositories to hold our tweet app images. Repositories are how images are organized within a DTR server. Each image gets pushed to its own repository. Multiple images can be stored within a repository by supplying a different tag to each version.\n\n2. Click the green `New repository` button on the right hand side of the screen. This brings up the new repository dialog\n\n3. Under `REPOSITORY NAME` type `linux_tweet_app` and click `Save`\n\nLet's repeat this process to create a repository for our Windows tweet app.\n\n4. Click the green `New repository` button on the right hand side of the screen. This brings up the new repository dialogue.\n\n5. Under `REPOSITORY NAME` type `windows_tweet_app` and click `Save`\n\nCongratulations you've installed Docker Trusted Registry, and have created two new repositories.\n\n### \u003ca name=\"task1.5\"\u003e\u003c/a\u003eTask 1.5: Install Self Signed Certs on All Nodes\n\nDocker uses TLS to ensure the identity of the Docker Trusted Registry. In a production environment you would use certs that come from a trusted certificate authority (CA). However, by default when you install UCP and DTR they use self-signed certs. These self-signed certs are not automatically trusted by the Docker engine. In order for them to be trusted, we need to copy down the root CA cert from the DTR server onto each node in the cluster. There is a script on each of your nodes that will do this for you\n\n\u003e **Note**: This step is only necessary in POC environments where trusted 3rd party certs are not used\n\nPerform the following steps on all 4 of your Linux nodes (pod-X-lin01, pod-X-lin02, pod-X-lin03, pod-X-lin04)\n\n![](./images/linux75.png)\n\n1. SSH into the Linux node\n\n2. At the command prompt run the `copy_certs` script passing it the ip address of your linux lin02 node.\n\n\t`$ ./copy_certs.sh \u003cpod-X-lin02 Ip address\u003e`\n\n\tYou should see the following output\n\n\n\t\t% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n\t\t100  1988  100  1988    0     0   7216      0 --:--:-- --:--:-- --:--:--  7229\n\t\tUpdating certificates in /etc/ssl/certs...\n\t\t1 added, 0 removed; done.\n\t\tRunning hooks in /etc/ca-certificates/update.d...\n\t\tdone.\n\n\u003e **Note**: In some cases you may see some Perl warnings in addition to the above output, these can be safely ignored.\n\n3. Log into the DTR server from the command line to ensure the cert was copied correctly. The username should be `docker` and the password `Docker2017`\n\n\t\u003e **Note**: Be sure to substitute the FQDN of your **B** Linux node\n\n\t\u003e **Note**: If you see an x509 certificate is from an unknown source error the cert didn't copy correctly, just rerun the above command.\n\n\t```\n\t$ docker login \u003cpod-X-lin02 IP Address\u003e\n\tUsername: docker\n\tPassword: Docker2017\n\t```\n\n\tYou should see a `Login succeeded` message\n\n\u003e **Note**: Remember to repeat these steps on all 4 Linux nodes.\n\n![](./images/windows75.png)\n\nNow we need to do something similar on the two Windows nodes. Perform the following steps on each of the two Windows nodes.\n\n1. RDP into the Windows node\n\n2. From the start menu, open a Powershell window\n\n3. Execute the `copy_certs` script\n\n\t`c:\\copy_certs.ps1 \u003cpod-X-lin02 Ip Address\u003e`\n\n3. Log into the DTR server from the command line to ensure the cert was copied correctly. The username should be `docker` and the password `Docker2017`\n\n\t\u003e **Note**: Be sure to substitute the IP Address of pod-X-lin02 Linux node\n\n\t\u003e **Note**: If you see an x509 certificate is from an unknown source error the cert didn't copy correctly, just rerun the above command.\n\n\t```\n\t$ docker login \u003cpod-X-lin02 Ip Address\u003e\n\tUsername: docker\n\tPassword: Docker2017\n\t```\n\n\tYou should see a `Login succeeded` message\n\u003e\nCongratulations, your nodes are now configured to work with your DTR instance.\n\n\n## \u003ca name=\"task2\"\u003e\u003c/a\u003eTask 2: Deploy a Linux Web App\n\nNow that we've built our cluster, let's deploy a couple of web apps. These are simple web pages that allow you to send a tweet. One is built on Linux using NGINX and the other is build on Windows Server 2016 using IIS.  \n\nLet's start on the Linux node.\n\n### \u003ca name=\"task2.1\"\u003e\u003c/a\u003e Task 2.1: Clone the Demo Repo\n\n![](./images/linux75.png)\n\n1. SSH in to your Linux **A** node\n\n2. Make sure you're in your home directory on your Linux VM\n\n\t`$ cd ~`\n\n2. Use git to clone the workshop repository.\n\n\t```\n\t$ git clone https://github.com/mikegcoleman/hybrid-workshop.git\n\t```\n\n\tYou should see something like this as the output:\n\n\t```\n\tCloning into 'hybrid-workshop'...\n\tremote: Counting objects: 13, done.\n\tremote: Compressing objects: 100% (10/10), done.\n\tremote: Total 13 (delta 1), reused 10 (delta 1), pack-reused 0\n\tUnpacking objects: 100% (13/13), done.\n\tChecking connectivity... done.\n\t```\n\n\tYou now have the necessary demo code on your Linux VM.\n\n### \u003ca name=\"task2.2\"\u003e\u003c/a\u003e Task 2.2: Build and Push the Linux Web App Image\n\n![](./images/linux75.png)\n\n1. Change into the `linux_tweet_app` directory.\n\n\t`$ cd ~/hybrid-workshop/linux_tweet_app/`\n\n2. Use `docker build` to build your Linux tweet web app Docker image.\n\n\t`$ docker build -t \u003cpod-X-lin02 IP Address\u003e/docker/linux_tweet_app .`\n\n\tThe `-t` tells Docker that you're going to store this image in the `docker` repo on your Docker Trusted Registry node\n\n\t\u003e **Note**: Feel free to examine the Dockerfile in this directory if you'd like to see how the image is being built.\n\n\tYour output should be similar to what is shown below\n\n\t```\n\tSending build context to Docker daemon  4.096kB\n\tStep 1/4 : FROM nginx:latest\n\tlatest: Pulling from library/nginx\n\tff3d52d8f55f: Pull complete\n\tb05436c68d6a: Pull complete\n\t961dd3f5d836: Pull complete\n\tDigest: sha256:12d30ce421ad530494d588f87b2328ddc3cae666e77ea1ae5ac3a6661e52cde6\n\tStatus: Downloaded newer image for nginx:latest\n\t ---\u003e 3448f27c273f\n\tStep 2/4 : COPY index.html /usr/share/nginx/html\n\t ---\u003e 72d22997a765\n\tRemoving intermediate container e262b9220942\n\tStep 3/4 : EXPOSE 80 443\n\t ---\u003e Running in 54e4ff1b39a6\n\t ---\u003e 2b5bd87894cd\n\tRemoving intermediate container 54e4ff1b39a6\n\tStep 4/4 : CMD nginx -g daemon off;\n\t ---\u003e Running in 54020cdec942\n\t ---\u003e ed5f550fc339\n\tRemoving intermediate container 54020cdec942\n\tSuccessfully built ed5f550fc339\n\tSuccessfully tagged  pod-1-lin02/docker/linux_tweet_app:latest\n\t```\n\n4. Use `docker push` to upload your image up to Docker Trusted Registry.\n\n\t\u003e **Note**: You should still be logged into DTR from the previous steps, but if not you will need to log in again.\n\n\t```\n\t$ docker push \u003cpod-X-lin02 IP Address\u003e/docker/linux_tweet_app\n\t```\n\n\tThe output should be similar to the following:\n\n\t```\n\tThe push refers to a repository [pod-1-lin02/docker/linux_tweet_app]\n\tfeecabd76a78: Pushed\n\t3c749ee6d1f5: Pushed\n\taf5bd3938f60: Pushed\n\t29f11c413898: Pushed\n\teb78099fbf7f: Pushed\n\tlatest: digest: sha256:9a376fd268d24007dd35bedc709b688f373f4e07af8b44dba5f1f009a7d70067 size: 1363\n\t```\n\n4. In your web browser head back to your DTR server and click `View Details` next to your `linux_tweet_app` repo to see the details of the repo.\n\n5. Click on `Images` from the horizontal menu. Notice that your newly pushed image is now on your DTR.\n\n### \u003ca name=\"task2.3\"\u003e\u003c/a\u003e Task 2.3: Deploy the Web App using UCP\n\nNow let's run our application by by creating a new service.\n\nServices are application building blocks (although in many cases an application will only have one service, such as this example). Services are based on a single Docker image. Tasks are the individual Docker containers that execute the application. When you create a new service you instantiate at least one task automatically, but you can scale the number of tasks up to meet the needs of your service.\n\n1. In your web browser navigate to your UCP server (`https://\u003cpod-X-lin01 IP Address`)\n\n2. In the left hand menu click `Services`\n\n3. In the upper right corner click `Create Service`\n\n4. Enter `linux_tweet_app` for the name.\n\n4. Under `Image` enter the path to your image which should be `\u003clinux node b fdqn/docker/linux_tweet_app`\n\n5. From the left hand menu click `Scheduling`\n\n6. A few lines down the screen click `Add Constraint+`.\n\n\tConstraints are used to tell UCP where to run workloads. They are based on labels - in this specific case we're using a built in label that tells us what OS a given node is running (`node.platform.os`). Since this is a Linux-based container we need to make sure it ends up on a Linux node.\n\n7. Enter `node.platform.os == Linux` into the text field\n\n\t![](./images/linux_constraint.png)\n\n8. From the left hand menu click `Network`\n\n9. Click `Publish Port+`\n\n\tWe need to open a port for our web server. Since port 80 is already used by UCP on one node, and DTR on the other, we'll need to pick an alternate port. We'll go with 8088.\n\n10. Fill out the port fields as shown below\n\n\t![](./images/linux_ports.png)\n\n11. Click `Confirm`\n\n12. Click `Create` near the bottom right of the screen.\n\nAfter a few seconds you should see a green dot next to your service name. Once you see you green dot you can  point your web browser to `http://\u003clinux node c fqdn\u003e:8088` to see your running website.\n\n\u003e **Note**: You want to go to `http://` not `https://`\n\n## \u003ca name=\"task3\"\u003e\u003c/a\u003eTask 3: Deploy a Windows Web App\n\nNow we'll deploy the Windows version of the tweet app.\n\n### \u003ca name=\"task3.1\"\u003e\u003c/a\u003e Task 3.1: Create the dockerfile with Image2Docker\n\nThere is a Windows Server 2016 VHD that contains our Windows Tweet App stored in `c:\\` on your cloud-based VM. We're going to use Image2Docker to scan the VHD, and create a Dockerfile. We'll build the Dockerfile as we did in the previous step, push it to DTR, and then deploy our Windows tweet app.\n\n![](./images/windows75.png)\n\n1. Move back to Windows node **A**, and open a PowerShell window.\n\n2. Use Image2Docker's `ConvertTo-Dockerfile` command to create a dockerfile from the VHD.\n\n\tCopy and paste the command below into your Powershell window.\n\n\t```\n\tConvertTo-Dockerfile -ImagePath c:\\ws2016.vhd `\n\t                     -Artifact IIS `\n\t                     -OutputPath C:\\windowstweetapp `\n\t                     -Verbose\n\t```\n\n\n\t* `ImagePath` specifies where the VHD can be found\n\n\t* `Artifact` specifies what feature or code to look for\n\n\t* `OutputPath` specifies where to write the dockerfile and other items\n\n\t* `Verbose` instructs the script to provide extra output.\n\nWhen the process completes you'll find a dockerfile in `c:\\windowstweetapp`\n\n\n### \u003ca name=\"task3.2\"\u003e\u003c/a\u003e Task 3.2: Build and Push Your Image to Docker Trusted Registry\n\n![](./images/windows75.png)\n\n1. CD into the directory where your Image2Docker files have been placed.\n\n\t`PS C:\\Users\\docker\u003e cd c:\\windowstweetapp\\ `\n\n\n2. Use `docker build` to build your Windows tweet web app Docker image.\n\n\t`$ docker build -t \u003cpod-X-lin02 IP Address\u003e/docker/windows_tweet_app .`\n\n\t\u003e **Note**: Be sure to use the FQDN for Linux node **B** when you tag the image.\n\n\t\u003e **Note**: Feel free to examine the Dockerfile in this directory if you'd like to see how the image is being built.\n\n\tYour output should be similar to what is shown below\n\n\t```\n\tPS C:\\Users\\docker\\scm\\hybrid-workshop\\windows_tweet_app\\docker build -t \u003clinux node b fqdn\u003e/docker/windows_tweet_app .\n\n\tSending build context to Docker daemon  6.144kB\n\tStep 1/10 : FROM microsoft/windowsservercore\n\t ---\u003e 590c0c2590e4\n\n\t\u003coutput snipped\u003e\n\n\tStep 10/10 : HEALTHCHECK CMD powershell -command     try {      $response = Invoke-WebRequest http://localhost -UseBasic\n\tParsing;      if ($response.StatusCode -eq 200) { return 0}      else {return 1};     } catch { return 1 }\n\t ---\u003e Running in ab4dfee81c7e\n\t ---\u003e d74eead7f408\n\tRemoving intermediate container ab4dfee81c7e\n\tSuccessfully built d74eead7f408\n\tSuccessfully tagged \u003clinux node b fqdn\u003e/docker/windows_tweet_app:latest\n\t```\n\t\u003e **Note**: It will take a few minutes for your image to build. If it takes more than 5 minutes move into your powershell window and press `Enter`. Sometimes the Powershell window will not update the current status of the build process.\n\n4. Log into Docker Trusted Registry\n\n\t```\n\tPS C:\\Users\\docker\u003e docker login \u003cpod-X-lin02 IP Address\u003e\n\tUsername: docker\n\tPassword: Docker2017\n\tLogin Succeeded\n\t```\n\n5. Push your new image up to Docker Trusted Registry.\n\n\t```\n\tPS C:\\Users\\docker\u003e docker push \u003cpod-X-lin02 IP Address\u003e/docker/windows_tweet_app\n\tThe push refers to a repository [\u003cpod-X-lin02 IP Address\u003e/docker/windows_tweet_app]\n\t5d08bc106d91: Pushed\n\t74b0331584ac: Pushed\n\te95704c2f7ac: Pushed\n\t669bd07a2ae7: Pushed\n\td9e5b60d8a47: Pushed\n\t8981bfcdaa9c: Pushed\n\t25bdce4d7407: Pushed\n\tdf83d4285da0: Pushed\n\t853ea7cd76fb: Pushed\n\t55cc5c7b4783: Skipped foreign layer\n\tf358be10862c: Skipped foreign layer\n\tlatest: digest: sha256:e28b556b138e3d407d75122611710d5f53f3df2d2ad4a134dcf7782eb381fa3f size: 2825\n\t```\n### \u003ca name=\"task3.3\"\u003e\u003c/a\u003e Task 3.3: Deploy the Windows Web App\nNow that we have our Windows Tweet App up on the DTR server, let's deploy it. It's going to be almost identical to how did the Linux version with a couple of small exceptions:\n\n* We will use a constraint to put the workload on a Windows node instead of Linux\n* Windows does not currently support ingress load balancing, so we'll exposer the ports in `host` mode using `dnsrr`\n\n1. In your web browser navigate to your UCP server (`https://\u003cpod-X-lin02 IP Address\u003e`)\n\n2. In the left hand menu click `Services`\n\n3. In the upper right corner click `Create Service`\n\n4. Enter `windows_tweet_app` for the name.\n\n4. Under `Image` enter the path to your image which should be `\u003cpod-X-lin02 IP Address\u003e/docker/windows_tweet_app`\n\n5. From the left hand menu click `Scheduling`\n\n6. A few lines down the screen click `Add Constraint+`.\n\n\tConstraints are used to tell UCP where to run workloads. They are based on labels - in this specific case we're using a built in label that tells us what OS a given node is running (`node.platform.os`). Since this is a Linux-based container we need to make sure it ends up on a Linux node.\n\n7. Enter `node.platform.os == windows` into the text field\n\n8. From the left hand menu click `Network`\n\n8. Set the `ENDPOINT SPEC` to `DNS Round Robin`. This tells the service to load balance using DNS. The alternative is VIP, which uses IPVS.\n\n9. Click `Publish Port+`\n\n\tWe need to open a port for our web server. This app runs on port 80 which is used by DTR so let's use 8082.\n\n10. Fill out the port fields as shown below. **Be sure to set the `Publish Mode` to  `Host`**\n\n\t![](./images/windows_ports.png)\n\n11. Click 'Confirm'\n\n12. Click `Create` near the bottom right of the screen.\n\nAfter a few seconds you should see a green dot next to your service name. Once you see you green dot you can  point your web browser to `http://\u003cpod-X-win05 IP Address\u003e:8082` to see your running website.\n\n\u003e **Note**: You want to go to your Windows node b, and use `http:// ` not `https:// `\n\n## \u003ca name=\"task4\"\u003e\u003c/a\u003e Deploying a Multi-OS Application\n\nFor our last exercise we'll use a docker compose file to deploy an application that uses a Java front end designed to be deployed on Linux, with a Microsoft SQL Server back end running on windows.\n\n### \u003ca name=\"task4.1\"\u003e\u003c/a\u003e Task 4.1: Examine the Docker Compose file\n\nWe'll use a Docker Compose file to instantiate our application. With this file we can define all our services and their parameters, as well as other Docker primatives such as networks.\n\nLet's look at the Docker Compose file:\n\n```\nversion: \"3.2\"\n\nservices:\n\n  database:\n    image: sixeyed/atsea-db:mssql\n    ports:\n      - mode: host\n        target: 1433\n    networks:\n     - atsea\n    deploy:\n      endpoint_mode: dnsrr\n      placement:\n        constraints:\n          - 'node.platform.os == windows'\n\n  appserver:\n    image: sixeyed/atsea-app:mssql\n    ports:\n      - target: 8080\n        published: 8080\n    networks:\n      - atsea\n    deploy:\n      placement:\n        constraints:\n          - 'node.platform.os == linux'\n\nnetworks:\n  atsea:\n```\n\nThere are two services. `appserver` is our web frontend written in Java, and `database` is our Microsoft SQL Server database. The rest of the commands should look familiar as they are very close to what we used when we deployed our tweet services manually.\n\nOne thing that is new is the creation of an overlay network (`atsea`). Overlay networks allow containers running on different hosts to communicate over a private software-defined network. In this case, the web frontend on our Linux host will use the `atsea` network to communicate with the database.\n\nYou may have used Docker Compose before to deploy multi-service applications, but with swarm we use a slightly different command: `docker stack`.\n\n### \u003ca name=\"task4.2\"\u003e\u003c/a\u003e Task 4.2: Deploy the Application\n\n1. Move to the UCP console in your web browser\n\n2. In the left hand menu click `stacks`\n\n3. In the upper right click `Create Stack`\n\n4. Enter `atsea` under `NAME`\n\n5. Select `Services` under `MODE`\n\n6. Select `SHOW VERBOSE COMPOSE OUTPUT`\n\n7. Paste the compose file from above into the `COMPOSE.YML` box\n\n8.  Click `Create`\n\n\tYou will see some output to show the progress of your deployment, and then a banner will pop up at the bottom indicating your deployment was successful.\n\n9. Click `Done`\n\nThe UI shows your stack (`atsea`) and that it's comprised of 2 services and 1 network.\n\n1. Click on the `atsea` stack in the list\n\n2. From the right side of the screen choose `Services` under `Inspect Resource`\n\n\t![](./images/inspect_resource.png)\n\n\tHere you can see your two services running. It may take a few minutes for the databased service to come up (the dot to turn green). Once it does move on to the next section.\n\n\n### \u003ca name=\"task4.3\"\u003e\u003c/a\u003e Task 4.3: Verify the Running Application\n\n1. To see our running web site (an art store) visit `http://\u003cpod-X-lin01:8080\u003e`\n\n\t\u003e **Note**: You want to go to `http:// ` not `https:// `\n\n\tThe thumbnails you see displayed are actually pulled from the SQL database. This is how you know that the connection is working between the database and web front end.\n\n\nThis concludes our workshop, thanks for attending.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-yu%2Fcisco-docker-mta-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavid-yu%2Fcisco-docker-mta-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavid-yu%2Fcisco-docker-mta-workshop/lists"}