Showing posts with label docker hub. Show all posts
Showing posts with label docker hub. Show all posts

Monday, February 21, 2022

Deploy single container docker image to Azure App Services

You have a self contained web app that runs in a docker container and want to deploy it on a cloud service. I will show you how easy it is to deploy your docker image to Azure App Services. I will, as an example use a simple Node.js Express web app in this demonstration.

Source code: https://github.com/medhatelmasry/xpress-sqlite-chart-docker.git

Assumptions:

  • Node.js and NPM are installed on your computer
  • Docker Desktop is installed on your computer
  • You have an Azure subscription
  • Git is installed on your computer
  • You have a docker hub account

Getting started

In a previous article, I created a Node.js Express app that persists data in SQLite. I will use this sample app i this article. 

Clone the Node.js Express sample web app on GitHub by running the following command from a working directory in a terminal window on your computer:

git clone https://github.com/medhatelmasry/xpress-sqlite-chart

Change into the newly cloned directory with:

cd xpress-sqlite-chart

The application is a simple Node.js Express application that uses SQLite as a database. This will come as a surprise to most Node.js developers because MongoDB is the most commonly used database with Node.js. The reason I used SQLite in this case is because it does not need a database server and can run independently in a docker container. To experience what this web app does, run the following commands in the same folder:

npm install
npm start

This will display in the console:

Server running on port 3000
Connected to the SQLite database.

Point your browser to http://localhost:3000/api/students and you will see the following output:


You can view a pie-chart summarizing the above information at http://localhost:3000/chart.html as shown below:


This data is being dynamically read from a SQLite database file named school.db located in the root of the web app.

Building our docker image

Stop the Node.js app by hitting CTRL C on the keyboard. 

Let us build a web app image and deploy it to docker hub.

We do not need to copy folder node_modules. Also, we should not copy school.db into the image because it is automatically created when the web app starts. Therefore, add a text file named .dockerignore with the following content:

school.db
node_modules

Add another text file named Dockerfile containing the instructions for creating our Docker image:

FROM node:12.18.1
WORKDIR /app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]


I am hereby using snoopy a an example docker-hub username. Be sure to replace every instance of snoopy with your docker-hub user name.

The command to build a Docker image named bingo version 1.0.0 is:

docker build --tag snoopy/bingo:1.0.0 .

Note: Make sure you run the above command in the same folder as Dockerfile.

To ensure that you created an image named asp-bingo, type the following command:

docker images

You will see your newly created image in a list of Docker images:



Let us run the image in a container to make sure that it works as expected:

docker run -d -p 8888:3000 --name bingo snoopy/bingo:1.0.0

Point your browser to http://localhost:8888/api/students and you should see student JSON data. This confirms to us that our image and container work. Stop and remove the container with the following command:

docker rm -f bingo

We can now push our image to docker hub. First we need to login into docker-hub with the following command:

docker login --username=snoopy

You will be prompted for your password. If all goes well. you will see the following output:

Login Succeeded

Logging in with your password grants your terminal complete access to your account. For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

We now need to push our image to docker-hub with:

docker push snoopy/bingo:1.0.0

The output will be similar to this:

The push refers to repository [docker.io/snoopy/bingo]
c8b45ef9554a: Pushed 
e98b0d58d677: Pushed 
5ffdad44213c: Pushed 
db7819aa4316: Pushed 
6be3db87bf2b: Mounted from library/node 
640ef100e22c: Mounted from library/node 
f5efc9f25bb5: Mounted from library/node 
6c4912a00957: Mounted from library/node 
47b172bd2907: Mounted from library/node 
38a97d5a6ebd: Mounted from library/node 
bfdc94824303: Mounted from library/node 
33c19d48a4f3: Mounted from library/node 
db4e0d4c0410: Mounted from library/node 
1.0.0: digest: sha256:32d22b3fd5f66a8c8e11bc3566b330e8085edb809f78fa7ca04f8e27bcab3ed6 size: 3051

If you login into https://hub.docker.com, you will find that the newly pushed image is sitting in your repository.

Deploying solution to Azure App Services

Login into Azure by going to the portal at https://portal.azure.com. Click on "App Services" on the left-side hamburger menu:



Click on Create:


Add a new resource group and complete the remaining settings as shown below:


The most important setting you need for Publish is "Docker Container".

Click on the "Next : Docker >" button. On the next screen choose:

Options: Single Container
Image Source: Docker Hub
Access Type: Public
Image and tag: enter the fully qualified name of your docker image
Startup Command: leave blank

Click on Review + Create then click on Create. You will see a blue "Go to resource" button once the deployment is completed.

Click on "Go to resource". This takes you to the control page for your web app. 


Click  the link on the top right-side as shown above. The web app should show in the browser.


If you want to see something more interesting, point to page /chart.html:


I trust that you have a good appreciation of how easy it is to deploy a containerized web app to the Azure App Services.


Sunday, January 23, 2022

Deploy multi-container docker-compose solution on Azure

In this tutorial I will show you how to deploy a multi-container solution to Azure. The example I will use is an ASP.NET 6.0 Razor web app that works with a SQL Server database. The web app and database server run in separate containers. We will setup the solution on the Azure portal.

Assumptions

  • .NET 6.0 is installed on your computer
  • Docker Desktop is installed on your computer
  • You have an Azure subscription
  • Git is installed on your computer
  • You have a docker hub account

Getting started

In a previous example, I discuss docker-compose with ASP.NET 6.0 & SQL Server.

Clone the ASP.NET 6.0 sample startup application by running the following command from a working directory on your computer:

git clone https://github.com/medhatelmasry/AspMsSQL-docker-compose

Change into the newly cloned directory with:

cd AspMsSQL-docker-compose

The application is a simple ASP.NET 6.0 Razor application that should be very familiar to any .NET developer. 

To understand how you can run this solution, you must inspect the following two files:

Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY dist /app
WORKDIR /app
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "AspMsSQL.dll"]

Docker file is used to build the web app. In line 2 above, the dist folder is copied into the image. Therefore, we must create a dist folder with the following command:

dotnet publish -o dist

docker-compose.yml

version: '3.8'

services:
  db:
    image: mcr.microsoft.com/azure-sql-edge
    
    volumes:
      - sqlsystem:/var/opt/mssql/
      - sqldata:/var/opt/sqlserver/data
      - sqllog:/var/opt/sqlserver/log
      - sqlbackup:/var/opt/sqlserver/backup

    ports:
      - "1433:1433"
    restart: always
    
    environment:
      ACCEPT_EULA: Y
      MSSQL_SA_PASSWORD: SqlPassword!

  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - db
    ports:
      - "8888:80"
    restart: always
    environment:
      - DBHOST=db
      - DBPORT=1433
      - DBUSER=sa
      - DBPASSWORD=SqlPassword!
      - DBNAME=YellowDB
      - ASPNETCORE_ENVIRONMENT=Development

volumes:
  sqlsystem:
  sqldata:
  sqllog:
  sqlbackup:

The db service above starts a SQL Server container from mcr.microsoft.com/azure-sql-edge.

The webapp service builds an image from Dockerfile and runs it. The web app can be accessed on the host computer with http://localhost:8888.

Running the solution on your computer

To run the application on your computer, type the following command from within the root folder of the web app (I.E. inside the AspMsSQL-docker-compose folder):

docker-compose up

Once the script in the terminal windows settles down, point your browser to http://localhost:8888. You will see the following landing page:



Register and login to ensure that the app functions properly with the database.

Cleanup

Let's shutdown and cleanup resources on our computer.

Inside of the terminal window that is running docker-compose, hit Ctrl C on your keyboard to stop the services. Thereafter, enter the following terminal command:

docker-compose down

To remove the webapp docker image, type:

docker rmi -f aspmssql-docker-compose_webapp

To remove all the volumes that were created on your computer, type:

docker volume rm aspmssql-docker-compose_sqlbackup
docker volume rm aspmssql-docker-compose_sqldata
docker volume rm aspmssql-docker-compose_sqllog
docker volume rm aspmssql-docker-compose_sqlsystem

Prepare solution for Azure deployment

We need to make one minor tweak so that our application can run on Azure. The tweak is to build the web app image and deploy it to docker hub.

I am hereby using snoopy a an example docker-hub username. Be sure to replace every instance of snoopy with your docker-hub user name.

The command to build a Docker image named asp-mssql version 1.0.0 is:

docker build --tag snoopy/asp-mssql:1.0.0 .

Note: Make sure you run the above command in the same folder as Dockerfile.

You ensure that you created an image named asp-mssql, type the following command:

docker images

You will see the image that you created among the list of docker images on your computer.

We can now push our image to docker hub. First we need to login into docker-hub with the following command:

docker login --username=snoopy

You will be prompted for your password. If all goes well. you will see the following output:

Login Succeeded


Logging in with your password grants your terminal complete access to your account.

For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

We now need to push our image to docker-hub with:

docker push snoopy/asp-mssql:1.0.0

The output will be similar to this:

The push refers to repository [docker.io/snoopy/asp-mssql]

5f70bf18a086: Mounted from snoopy/toon
3b9aa4fcf4e8: Pushed
a41af57309b5: Mounted from snoopy/toon
63fa163dde0c: Mounted from snoopy/toon
0f53df05d8e3: Mounted from snoopy/toon
bc1e58de0815: Mounted from snoopy/toon
2edcec3590a4: Mounted from snoopy/toon

If you login to https://hub.docker.com, you will find that the image is sitting in your repository.

Let's modify our docker-compose.yml file so that it used this image on docker-hub instead of building it locally. Open docker-compose.yml in an editor and replace lines 22-24 with:

image: snoopy/asp-mssql:1.0.0

Needless to say that instead of snoopy, you should use your docker-hub username.

The final docker-compose.yml will look like this:

version: '3.8'
services:
  db:
    image: mcr.microsoft.com/azure-sql-edge
    
    volumes:
      - sqlsystem:/var/opt/mssql/
      - sqldata:/var/opt/sqlserver/data
      - sqllog:/var/opt/sqlserver/log
      - sqlbackup:/var/opt/sqlserver/backup
    ports:
      - "1433:1433"
    restart: always
    
    environment:
      ACCEPT_EULA: Y
      MSSQL_SA_PASSWORD: SqlPassword!
  webapp:
    image: snoopy/asp-mssql:1.0.0
    depends_on:
      - db
    ports:
      - "8888:80"
    restart: always
    environment:
      - DBHOST=db
      - DBPORT=1433
      - DBUSER=sa
      - DBPASSWORD=SqlPassword!
      - DBNAME=YellowDB
      - ASPNETCORE_ENVIRONMENT=Development
volumes:
  sqlsystem:
  sqldata:
  sqllog:
  sqlbackup:

Deploying solution to Azure

Login into Azure by going to the portal at https://portal.azure.com. Click on "App Services" on the left-side hamburger menu:



Click on Create:

Add a new resource group:



Here are the remaining settings that I chose:


The most important setting you need to have for Publish is "Docker Container".

Click on the "Next : Docker >" button. On the next screen choose:

Options Docker Compose (Preview)
Image Source Docker Hub
Access Type Public
Configuration File Navigate to the docker-compose.yml file and load it. It will load in the text-area below.

This is what it should look like:


Click on "Review + create" button.


Review the configuration then click on Create.

You will see a blue "Go to resource" button once the deployment is completed.

Click on "Go to resource". This takes you to the control page for your web app. 


Click on the URL on the top right-side to see your solution running in the browser. Be patient because the solution takes some time to load. In my case, the app displayed like this:


At the time of writing this article, the Docker Compose capability in Azure App services is in preview mode. It seems to work quite well and, I am confident, it will be production ready soon.

Monday, December 20, 2021

Deploy multi-container app to Azure App Service with docker-compose

In this article, I will show how easy it is to deploy a multi-container application to Azure App Service using a docker-compose.yml file. This service is currently in preview on Azure. The example is deployment of a WordPress site on the Azure portal. This involves two containers on docker hub, namely: mysql:8.0.0 and wordpress:5.8.2-php7.4-apache.

The only pre-requisite is that you have a valid Azure subscription.

Save the following to a text file named docker-compose.yml:

version: '3.1'

services:

  wordpress:
    image: wordpress:5.8.2-php7.4-apache
    restart: always
    ports:
      - 8888:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html

  db:
    image: mysql:8.0.0
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:

Login to https://portal.azure.com. Create a new app service as follows:
  1. Create a new resource group
  2. Provide a unique host name for your app's URL
  3. Select 'Docker Container" for Publish
  4. Select Linux for the Operating System
  5. Choose a data center closest to your city


Click on the "Next Docker" button.
  1. Select 'Docker Compose (Preview)' for Options.
  2. Select 'Docker Hub' for Image Source
  3. Select Public for Access Type
  4. Beside 'Configuration File', navigate to the docker-compose.yml and select it.

Click on blue "Review + create" button.


Click on the blue Create button. It may take some time to provision the containers. Upon completion, you will see a page that looks like this:


Click on the blue "Go to resource" button.


Click on the URL to view the WordPress page.


Troubleshooting

If something goes wrong and you wish to look into the console logs:

1) Enter 'log' into the filter
2) Turn "App Service Logs" ON



3) Click Save at the top
4) Click on "Log stream"



Cleanup

If you do not need these containers anymore, all you have to do to tear down everything is to delete the resource group.

Conclusion

It is painless to create a multi-container web application using docker-compose.yml.



Monday, May 11, 2020

CI/CD pipelines with ASP.NET MVC 3.1, GitHub Actions and Docker Hub

Overview

In this post I will show you how easy it is to implement a CI/CD DevOps pipeline using GitHub Actions. The sample web application I will use is an ASP.NET Core 3.1 MVC application and I will deploy it to Docker Hub. 
Before proceeding, It is assumed that you have the following pre-requisites: 
  • You already have a Docker Hub account
  • You already have a GitHub account
  • You have .NET Core 3.1 (or later) installed on your computer

Creating a simple ASP.NET Core 3.1 application

In a working directory, execute the following command from within a terminal window:

dotnet new mvc -o GithubActions2DockerHub

Change directory to the newly created app:

cd GithubActions2DockerHub

Add a .gitignore file to the application:

dotnet new gitignore

Let us make the application our own by, perhaps, changing the title of the app and the background color.

1) Add the following CSS to wwwroot/css/site.css:
body {
   background-color: tomato;
}

2) In Views/Home/Index.cshtml, change the main heading from:

<h1 class="display-4">Welcome</h1>

TO

<h1 class="display-4">Welcome to our MVC Core 3.1 App</h1>

Let us now run the application and see what it looks like. In the terminal window run the following command:

dotnet run

Point your browser to https://localhost:5001. You will see a strangely colored web page that looks like this:



Stop the server by hitting CTRL + C in the terminal window.

Dockerfile

In the root folder of your project, add a file named Dockerfile (no extension) with the following content:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "GithubActions2DockerHub.dll"]

Push your code to GitHub.

We are now ready to push this application to GitGub. Go to GitHub and create a repository. I created a repository named GithubActions2DockerHub. Copy the commands that are shown on the GitHub page, under “…or push an existing repository from the command line”, that looks like this:


Back in your application’s terminal window, type the following commands to initialize a git repo, add files to the repo and commit your changes:

git init
git add .
git commit -m "1st commit"

Next, we will push the code to GitHub. Paste the git commands that you copied from GitHub. This is what it looked like for me:

git remote add origin https://github.com/medhatelmasry/GithubActions2DockerHub.gitgit push -u origin master

If you refresh the GitHub page, you will see that your code is in GitHub. It looks like this:

Click on Secrets on the left-side:

Build & Deploy using GitHub Actions

 Back it GitHub, click on the Settings tab of your application’s repo:
 
Click on Secrets on the left-side:
Click on “Add a new secret”:
 You will enter your Docker Hub username and password as GitHub secrets. Enter secrets DOCKER_USERNAME & DOCKER_PASSWORD together with their respectivev values:
    
Click on Actions on the top navigation bar in GitHub:
You will see a multitude of templates for a multitude of technologies and programming languages. Scroll down to the “Continuous integration workflows” and select “Docker image”.
This will create a .github/Workflows folder in your application. Name the file deploy_to_docker_hub.yml. 
Your deploy_to_docker_hub.yml looks like this:
name: Docker Image CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

  jobs:

    build:

      runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Build the Docker image
        run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)

Unfortunately, the above instructions only build the docker file but do not deploy to docker hub. We will replace the instructions (under steps:) with instructions that checkout, build and deploy.

Therefore delete the following lines at the bottom of the deploy_to_docker_hub.yml file:

- name: Build the Docker image
run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)

Replace the above code with the following:

- uses: docker/build-push-action@v1
  with:
    username: ${{ secrets.DOCKER_USERNAME }}
    password: ${{ secrets.DOCKER_PASSWORD }}
    repository: melmasry/aspnetmvc
    tags: v1

The image will be named melmasry/aspnetmvc and the tag (version) will be v1.
Make sure tab the instructions in deploy_to_docker_hub.yml so that it is indented as shown below:

name: Docker Image CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:

  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - uses: docker/build-push-action@v1
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
        repository: melmasry/aspnetmvc
        tags: latest

NOTE: replace melmasry with your Docker Hub username.

Click on the green “Start commit” button:
Enter a comment and description for the commit then click on the “Commit new file” button:
 Click on “Actions” >> “All Workflows” >> your workflow.  
Then click on build:
The build and deploy should be succcessfully completed. The real test comes with pulling the image from DockerHub and running it locally on your computer. Run the following command from a terminal window on your computer:

docker run -d -p 8888:80 melmasry/aspnetmvc:latest

NOTE: replace melmasry with your Docker Hub username.
Point your browser to http://localhost:8888. You will see the same ugly tomato colored web page:
 
Happy coding!!

Wednesday, February 13, 2019

Deploy Node Express Docker Container to Azure

In this tutorial I will show you how to easily deploy a simple Node-Express docker image and run it from Azure containers. It is assumed that you have:
  • Docker installed on your computer
  • Git installed on your computer
  • You have a billable Azure account
  • You have a Docker hub account
  • You have installed the Azure CLI on your computer
Let us start with a very simple Node-Express application. I have one that you can clone from GitHub. Run the following command from a working directory in order to clone my simple Node-Express application:
Once you have cloned the application, you can create a Docker image named toon-node. View a file named Dockerfile located in the root of the application. This file looks like this:
# Create image based on the official Node 6 image from the dockerhub
FROM node:10.13.0-jessie

# Create a directory where our app will be placed
RUN mkdir -p /usr/src/app

# Change directory so that our commands run inside this new directory
WORKDIR /usr/src/app

# Copy dependency definitions
COPY package.json /usr/src/app

# Install dependecies
RUN npm install

# Get all the code needed to run the app
COPY . /usr/src/app

# Expose the port the app runs in
ENV PORT 80

# Serve the app
CMD ["npm", "start"]
This is what each command in Dockerfile does.
FROM node:10.13.0-jessie Base the new image on node:10:13.0-jessie
RUN mkdir -p /usr/src/app Create a directory /usr/src/app in the container
WORKDIR /usr/src/app Make /usr/src/app the working dir in the container
COPY package.json /usr/src/app Copy package.json on your computer into the working directory in the container
RUN npm install Execute "npm install" in the container
COPY . /usr/src/app Copy all files in the. current directory of your computer into the container’s working directory. Note that any files in .dockerignore will be ignored
ENV PORT 80 The node application inside the container will listen in on port 80
CMD ["npm", "start"] Launch the web application by executing “npm start”.
Create a Docker image with the following terminal command:
docker build -f Dockerfile -t snoopy/toons:toon-node . --no-cache
Note that you must prefix the image name with your Docker hub account. In the above example, snoopy represents your username on Docker hub.
Once the image is created, you can verify that it indeed exists by using the following Docker terminal command that lists on the images on your computer:
docker images
You should see an image named toons:toon-node prefixed by your Docker hub username.
Now let us run this Node-Express application to see what it does. We will create a container from the image that we just created. Run the following command to create a container whereby port 80 in the container is mapped to port 3000 on your computer:
docker run -p 3000:80 snoopy/toons:toon-node
You can then point your browser to http://localhost:3000 to see what the node-express application looks like. If all goes well, you should see the following web page:
 
The next thing we need to do is push our image to Docker hub. This is done by first logging-in into Docker hub with:
docker login
Note that this needs to be done only once on the computer.
You can then push the image to Docker hub with:
docker push snoopy/toons:toon-node
If you go to Docker hub at https://hub.docker.com/, you will see that the image exists in the toons repository. This is what my toons repository looked like on Docker hub:
With our image sitting in the Docker hub repository, we can now start using Azure to pull the image and run a container in Azure.
Login into Azure on your computer using the Azure CLI (command line interface). This is done by running the following terminal window command:
az login
This opens a browser window in which you will be authenticated. You can close the browser once you have successfully authenticated. 
We need to either use an existing resource group or. create a new one. I created a new resource group named toon-rg in data centre West-US2 with the following terminal window command:
az group create --location westus2 --name toon-rg 
Once you execute the above command, a successful response from the server will look similar to this:
{
  "id": "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/toon-rg",
  "location": "westus2",
  "managedBy": null,
  "name": "toon-rg",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": null
}

Let us use the image we have in Docker hub to run a container in Azure. This can be done by executing the following command:
az container create --name toon-c --resource-group toon-rg --image snoopy/toons:toon-node --ip-address public
These are what the above settings represent:
--name toon-c The container name is “toon-c".
--resource-group toon-rg The resource group name is “toon-rg".
--image snoopy/toons:toon-node The name of our image on Docker hub is "snoopy/toons:toon-node".
--ip-address public Respond with the public IP address so that we can run and verify that indeed our web site is working on Azure.
Remember that you must replace snoopy with your Docker hub username.
When I ran the last command, it took some time to run and I eventually got a long JSON response. I am showing you a part of the response that has the public IP address:
You can see the public IP address in the JSON response. If you point your browser to this IP address you should see the application running on Azure. This is what I experienced when I pointed my browser to http://52.247.209.239
It is rather impressive how easy it is to host a Docker container on Azure.