This article describes how the Linode CLI can help us achieve immutable deployments of static websites in the context of an automated CI/CD process. We´ll go through four steps, however, the process can vary depending on each team’s dynamics.
1. Get the site code and create the build artifact
During the first step the goal is to generate the static assets that will be deployed; we download the latest version of the code (most likely stored in a version control repository) and create the build artifact using tools like npm
or gulp
, obtaining all the required dependencies. This is done in a fresh environment folder, meaning no previous build is stored.
Although not described here, executing the corresponding unit tests before creating the build is recommended; it’s also a common quality gate for many applications.
Step 2. Create a bucket
Here we leverage the Linode SDK with the Object Storage plugin, called obj
linode obj [command]
where [command] will be the operation we want to execute. (You can find the usage guide here)
The immutability comes from creating a new bucket each time we deploy. This kind of task is usually done with CI/CD pipeline automated tools, like Jenkins, Azure DevOps, Gitlab, etc., where we can get information about the process execution that changes (increments) every time it runs. For Jenkins, it’d be something like
linode obj mb $BUILD_TAG
This will help us get a unique (incremental) name each time we execute. Of course, we need to be mindful of the bucket naming restrictions:
- It must be between 3 and 63 characters in length.
- It can only contain lower-case characters, numbers, periods, and dashes.
- It must start with a lowercase letter or number.
- It cannot contain underscores (_), end with a dash (-) or period (.), have consecutive periods (.), or use dashes (-) adjacent to periods (.).
- It cannot be formatted as IP addresses.
Our bucket will be created immediately. Next, we want to mark it as a static website using
linode obj ws-create $BUILD_TAG --ws-index=index.html --ws-error=404.html
Notice we’re using the same variable for the bucket name ($BUILD_TAG), making this process automated and repeatable using our CI/CD tool.
Step 3. Deploy our content
With the s3cmd tool we copy our website content recursively using the sync command
s3cmd --no-mime-magic --acl-public sync . s3://$BUILD_TAG
We’re using the following parameters:
- no-mime-magic: Tells Object Storage not to use file signatures when guessing the object’s MIME type.
- acl-public: Sets the access level control of the objects to “public.” This makes our website usable.
(Here’s an S3cmd guide)
At this point, we have a static website ready. We can access it using the URL, which has the following format
https://[BUCKET_NAME].website-us-southeast-1.linodeobjects.com
In this example, BUCKET_NAME
equals $BUILD_TAG
, meaning that we can construct the URL dynamically to use it further in the process, like running UI Tests using Puppeteer, Selenium, etc., depending on the quality gates we want to add to the process.
Step 4. Cleanup
Once our work is done, we want to eliminate our bucket so we don’t end up with tons of unused objects and ensure they don’t get reused by mistake. We use an empty folder for this; in this case, we create it during the pipeline execution since the process runs on a fresh environment folder each time.
mkdir clean
cd clean
then we use s3cmd
sync again
s3cmd --delete-removed --delete-after --force sync . s3://$BUILD_TAG
Notice we’re using different parameters
- delete-removed: Deletes any destination objects with no corresponding source file.
- delete-after: Deletes destination files no longer found at the source after all files are uploaded to the bucket.
- force: Confirm we’re syncing an empty folder, resulting in all existing files being deleted.
We need to do this since we cannot remove buckets that aren’t empty. Once completed, we delete the bucket using the Linode CLI again
linode obj rb $BUILD_TAG
Conclusion
The proposed process aims to facilitate the testing of static websites, which is useful when companies have separate teams for the front and back-end pieces of an application. This can also help teams working with the micro-frontend pattern, where small independent UI chunks are merged as if they were a single one.
The point here is to illustrate how the Linode CLI can be used to automate tasks of the software development lifecycle. The implementation will vary depending on team composition, practices, and tools.