Deploy a Container Web App on Amazon Lightsail

TUTORIAL

Module 4: Deploy a New Container Version

In this module, you will learn to update a container that has already been deployed

Overview

In the life of an application, it will be updated many times. In this module, you will learn how to update your deployment and how to roll back a deployment, in case the new application version has issues.

What you will accomplish

In this module, you will:
  • Update the application code and build a new local container image
  • Push the updated container image to Amazon Lightsail
  • Deploy the new version of your application
  • Roll back a deployment, in case something goes wrong

 Minimum time to complete

10 minutes

 Module prerequisites

  • AWS account with administrator-level access*
  • Recommended browser: The latest version of Chrome or Firefox

*Accounts created within the past 24 hours might not yet have access to the services required for this tutorial.

Implementation

Update your application code and build a new container image

Let's pretend the city name on the application front page is incorrect and needs to be modified.

Open the file code/templates/index.html. Search for Las Vegas and replace it with Paris.

Then, build and test the container as explained in module 2. Open a terminal and enter the following commands:

docker build -t demo-flask-signup .
docker run -p 8080:80 --rm -v ~/.aws:/root/.aws demo-flask-signup:latest

Now that the container is running, open a browser and point it at http://localhost:8080. You should see the application home screen, with the new city name.

Push the updated container image to Amazon Lightsail

Now that the container is built, the next step is to push this new container image to Amazon Lightsail.

Open a terminal and enter the following commands:

aws lightsail push-container-image --region eu-west-3 --service-name signup-application --label latest  --image demo-flask-signup:latest

The command outputs a message, such as the following:

# aws lightsail push-container-image --region eu-west-3 --service-name signup-application --label latest --image demo-flask-signup:latest

df0f7d33bb59: Pushed 
951ffe99d911: Pushed 
cee40450fe90: Pushed 
1327150a5178: Pushed 
4bc5d67b6427: Layer already exists 
ce8ffb5c560e: Layer already exists 
4226d5d0360f: Layer already exists 
9d1af766c818: Layer already exists 
d97733c0a3b6: Layer already exists 
c553c6ba5f13: Layer already exists 
48b4a40de359: Layer already exists 
ace9ed9bcfaf: Layer already exists 
764055ebc9a7: Layer already exists 
Digest: sha256:42d2e19ee7340bc7f028593318e9b7406e9e70fb4785618d3f6c78443e097a87
Image "demo-flask-signup:latest" registered.
Refer to this image as ":signup-application.latest.2" in deployments. 

The last line of the output displays the internal name of your container. Note the name because we will need it to deploy the container onto the container service. In case you want to access the container name at a later stage, you can enter the following command:

aws lightsail get-container-images --region eu-west-3 --service-name signup-application

The command outputs a message, such as the following:

# aws lightsail get-container-images --region eu-west-3 --service-name signup-application

{
    "containerImages": [
        {
            "image": ":signup-application.latest.2",
            "digest": "sha256:42d2e19ee7340bc7f028593318e9b7406e9e70fb4785618d3f6c78443e097a87",
            "createdAt": "2024-03-13T14:20:08-04:00"
        },
        {
            "image": ":signup-application.latest.1",
            "digest": "sha256:128f84907d30a1fb47c1888720485fa8050cc99bc1034e0cfd1f46d3b6e57e19",
            "createdAt": "2024-03-13T13:23:08-04:00"
        }
    ]
}

Issue the commands to check the deployment state.

Notice the "state": "DEPLOYING" status. After a while, the state will become ACTIVE. The deployment takes a few minutes to complete. You can check the state of your deployment using the following command:

aws lightsail get-container-services --region eu-west-3 --query "containerServices[].nextDeployment.state"
aws lightsail get-container-services --region eu-west-3 --query "containerServices[].currentDeployment.state" 

Test your deployment

To test your deployment, first retrieve the URL Lightsail created for you. Open a terminal and enter the following command:

aws lightsail get-container-services --region eu-west-3 --query "containerServices[].url"

The command outputs a message, such as the following:

# aws lightsail get-container-services --region eu-west-3 --query "containerServices[].url"

[
    "https://signup-application.me04fvc6dbk4e.eu-west-3.cs.amazonlightsail.com/"
]

We now have two versions of our container image - :signup-application.latest.1 and :signup-application.latest.2.

Deploy a new version of your application

Now that the container image is stored on Amazon Lightsail, we can deploy that image to the container service, using similar commands as described in the previous Deploy a Container module.

Edit the lc.json file and replace the name of the image to use—:signup-application.latest.1—to the new version :signup-application.latest.2.

The new lc.json file should look like this:

{
    "serviceName": "signup-application",
    "containers": {
        "signup-app-container": {
            "image": ":signup-application.latest.2",
            "ports": {
                "80": "HTTP"
            }
        }
    },
    "publicEndpoint": {
        "containerName": "signup-app-container",
        "containerPort": 80
    }
}

Then, deploy the container by entering the following command:

aws lightsail create-container-service-deployment --region eu-west-3 --cli-input-json file://lc.json

The command outputs a message, such as the following:

# aws lightsail create-container-service-deployment --region eu-west-3 --cli-input-json file://lc.json

{
    "containerService": {
        "containerServiceName": "signup-application",
        "arn": "arn:aws:lightsail:eu-west-3:012345678901:ContainerService/528a0bcf-fd14-42d4-a09a-943a241adc51",
        "createdAt": "2024-03-15T11:43:10-04:00",
        "location": {
            "availabilityZone": "all",
            "regionName": "eu-west-3"
        },
        "resourceType": "ContainerService",
        "tags": [],
        "power": "nano",
        "powerId": "nano-1",
        "state": "DEPLOYING",
        "scale": 2,
        "nextDeployment": {
            "version": 1,
            "state": "ACTIVATING",
            "containers": {
                "signup-app-container": {
                    "image": ":signup-application.latest.2",
                    "command": [],
                    "environment": {},
                    "ports": {
                        "80": "HTTP"
                    }
                }
            },
            "publicEndpoint": {
                "containerName": "signup-app-container",
                "containerPort": 80,
                "healthCheck": {
                    "healthyThreshold": 2,
                    "unhealthyThreshold": 2,
                    "timeoutSeconds": 2,
                    "intervalSeconds": 5,
                    "path": "/",
                    "successCodes": "200-499"
                }
            },
            "createdAt": "2024-03-15T11:43:10-04:00"
       },
        "isDisabled": false,
        "principalArn": "arn:aws:iam::577312533299:role/amazon/lightsail/eu-west-3/containers/signup-application/1jetjd21p8qshe57seuh71tnrnn29ps77lnno20sbgl2ghbuc0r0",
        "privateDomainName": "signup-application.service.local",
        "url": "https://signup-application.me04fvc6dbk4e.eu-west-3.cs.amazonlightsail.com/"
    }
}

Test your deployment

To test the deployment, switch to your browser window and refresh the page on the container service URL provided in the previous module.

You can retrieve the URL by entering this command in a terminal:

aws lightsail get-container-services --region eu-west-3 --query "containerServices[].url"

The command outputs a message, such as the following:

# aws lightsail get-container-services --region eu-west-3 --query "containerServices[].url"

[
    "https://signup-application.me04fvc6dbk4e.eu-west-3.cs.amazonlightsail.com/"
]

Roll back a deployment

The last deployment did not override the first version of the application; it just created a new version.

To verify the versions available, open a terminal and enter the following command:

aws lightsail get-container-service-deployments --region eu-west-3 --service-name signup-application

The command outputs a message, such as the following:

# aws lightsail get-container-service-deployments --region eu-west-3 --service-name signup-application

{
    "deployments": [
        {
            "version": 1,
            "state": "ACTIVE",
            "containers": {
                "signup-app-container": {
                    "image": ":signup-application.latest.1",
                    "command": [],
                    "environment": {},
                    "ports": {
                        "80": "HTTP"
                    }
                }
            },
            "publicEndpoint": {
                "containerName": "signup-app-container",
                "containerPort": 80,
                "healthCheck": {
                    "healthyThreshold": 2,
                    "unhealthyThreshold": 2,
                    "timeoutSeconds": 2,
                    "intervalSeconds": 5,
                    "path": "/",
                    "successCodes": "200-499"
                }
            },
            "createdAt": "2024-03-13T14:21:30-04:00"
        }
    ]
}

Reading the output of the previous command, you can observe there are two deployment versions. Version 1 is in an INACTIVE state, while version 2 is ACTIVE.

The following command gives a less detailed overview of your deployments:

aws lightsail get-container-service-deployments --region eu-west-3 --service-name signup-application --query 'deployments[].{version: version, state: state, image:containers.\"signup-app-container\".image}'

The command outputs a message, such as the following:

# aws lightsail get-container-service-deployments --region eu-west-3 --service-name signup-application --query 'deployments[].{version: version, state: state, image:containers.\"signup-app-container\".image}'

[
    {
        "version": 2,
        "state": "ACTIVE",
        "image": ":signup-application.latest.2"
    },
    {
        "version": 1,
        "state": "INACTIVE",
        "image": ":signup-application.latest.1"
    }
]

Now imagine the last version of the application you just deployed is not behaving correctly. Maybe a bug has not surfaced during the testing.

To access the log of your containers, open a terminal and enter the following command:

aws lightsail get-container-log --region eu-west-3 --service-name signup-application --container-name signup-app-container --output text

The command outputs a message, similar to the following:

# aws lightsail get-container-log --region eu-west-3 --service-name signup-application --container-name signup-app-container --output text

LOGEVENTS       2024-03-18T10:29:28-04:00       [deployment:1] Creating your deployment
LOGEVENTS       2024-03-18T10:30:03-04:00       Starting NGinx
LOGEVENTS       2024-03-18T10:30:03-04:00       2024/03/18 14:30:03 [notice] 13#13: using the "epoll" event method
LOGEVENTS       2024-03-18T10:30:03-04:00       2024/03/18 14:30:03 [notice] 13#13: nginx/1.25.4
LOGEVENTS       2024-03-18T10:30:03-04:00       2024/03/18 14:30:03 [notice] 13#13: built by gcc 12.2.0 (Debian 12.2.0-14)
...

To quickly roll back your deployment and redeploy the previous version of the application, change the lc.json file to make it use the first version of the container image and redeploy this image.

Modify the lc.json file to the following:

{
    "serviceName": "signup-application",
    "containers": {
        "signup-app-container": {
            "image": ":signup-application.latest.1",
            "ports": {
                "80": "HTTP"
            }
        }
    },
    "publicEndpoint": {
        "containerName": "signup-app-container",
        "containerPort": 80
    }
}

Then run the following command in the terminal:

aws lightsail create-container-service-deployment --region eu-west-3 --cli-input-json file://lc.json

The command outputs a message, similar to the following:

# aws lightsail create-container-service-deployment --region eu-west-3 --cli-input-json file://lc.json

{
    "containerService": {
        "containerServiceName": "signup-application",
        "arn": "arn:aws:lightsail:eu-west-3:607950359977:ContainerService/d9203026-b87b-4e6a-8a91-df2540dbfe86",
        "createdAt": "2024-03-18T10:25:22-04:00",
        "location": {
            "availabilityZone": "all",
            "regionName": "eu-west-3"
        },
        "resourceType": "ContainerService",
        "tags": [],
        "power": "nano",
        "powerId": "nano-1",
        "state": "DEPLOYING",
        "scale": 2,
        "currentDeployment": {
            "version": 2,
            "state": "ACTIVE",
            "containers": {
                "signup-app-container": {
                    "image": ":signup-application.latest.2",
                    "command": [],
                    "environment": {},
                    "ports": {
                        "80": "HTTP"
                    }
                }
            },
            "publicEndpoint": {
                "containerName": "signup-app-container",
                "containerPort": 80,
                "healthCheck": {
                    "healthyThreshold": 2,
                    "unhealthyThreshold": 2,
                    "timeoutSeconds": 2,
                    "intervalSeconds": 5,
                    "path": "/",
                    "successCodes": "200-499"
                }
            },
            "createdAt": "2024-03-18T10:41:11-04:00"
        },
        "nextDeployment": {
            "version": 3,
            "state": "ACTIVATING",
            "containers": {
                "signup-app-container": {
                    "image": ":signup-application.latest.1",
                    "command": [],
                    "environment": {},
                    "ports": {
                        "80": "HTTP"
                    }
                }
            },
            "publicEndpoint": {
                "containerName": "signup-app-container",
                "containerPort": 80,
                "healthCheck": {
                    "healthyThreshold": 2,
                    "unhealthyThreshold": 2,
                    "timeoutSeconds": 2,
                    "intervalSeconds": 5,
                    "path": "/",
                    "successCodes": "200-499"
                }
            },
            "createdAt": "2024-03-18T10:55:42-04:00"
        },
        "isDisabled": false,
        "principalArn": "arn:aws:iam::844358175455:role/amazon/lightsail/eu-west-3/containers/signup-application/1jetjd21p8qshe57seuh71tnrnn29ps77lnno20sbgl2ghbuc0r0",
        "privateDomainName": "signup-application.service.local",
        "url": "https://signup-application.oh6a4qb72ia80.eu-west-3.cs.amazonlightsail.com/",
        "privateRegistryAccess": {
            "ecrImagePullerRole": {
                "isActive": false,
                "principalArn": ""
            }
        }
    }
}

After a while, deployment v3, using container image v1 is ACTIVE. Deployments v2 and v1 are INACTIVE.

You can verify the first version is deployed by opening your browser and pointing it at the container service URL.

Conclusion

This is the end of this tutorial. Before taking a well-deserved break, be sure to clean up the environment to not accrue charges on your AWS account.

Up Next: Clean Up Resources

Was this page helpful?