Deploying a web application can be a challenging task, especially if you want to ensure that your application can handle high traffic, provide high availability, and comply with security and regulatory standards. Fortunately, there are tools and platforms that can help you achieve these goals, such as Aptible and Kubernetes.
Aptible is a platform that simplifies the deployment and management of secure and compliant web applications. Aptible provides features such as automated provisioning, encryption, backups, logging, monitoring, and auditing for your web applications. Aptible also helps you comply with various standards and regulations, such as HIPAA, SOC 2, ISO 27001, and GDPR. Learn More
Learn why Aptible's Engineering-Led Support and Production-Ready SLAs makes them a great choice for you. Read here
Kubernetes is an open-source system that automates the deployment, scaling, and management of containerized applications. Kubernetes allows you to run your web application in a cluster of servers, called nodes, that can be distributed across different regions and providers. Kubernetes also provides features such as load balancing, service discovery, self-healing, horizontal scaling, rolling updates, and more.
In this article, you will learn how to deploy a scalable web application with Aptible and Kubernetes. You will use Aptible to create a secure and compliant environment for your web application and Kubernetes to orchestrate the deployment and scaling of your web application across multiple nodes. You will also learn how to use some of the key concepts and components of Aptible and Kubernetes, such as:
Pods: The smallest unit of deployment in Kubernetes. A pod is a group of one or more containers that share the same network and storage resources.
Services: An abstraction that defines a logical set of pods and a policy to access them. A service provides a stable endpoint for your pods, regardless of their location or state.
Deployments: An abstraction that manages the creation and update of pods. A deployment allows you to specify the desired state of your pods, such as the number of replicas, the image version, the update strategy, etc. Kubernetes will ensure that your pods match the desired state.
Aptible Environments: A logical grouping of resources in Aptible. An environment consists of one or more apps, which are the web applications that you deploy with Aptible; one or more databases, which are the data stores that you provision with Aptible; and one or more endpoints, which are the entry points for accessing your apps and databases.
Prerequisites
Step 1: Create an Aptible app and configure your environment variables
Step 2: Build and push your web application image to a container registry
Step 3: Create a Kubernetes deployment and service for your web application
Step 4: Expose your web application service to the internet with Aptible endpoints
Step 5: Test and verify your web application deployment
Conclusion
To follow this article, you will need:
By the end of this article, you will have deployed a scalable web application with Aptible and Kubernetes and learned how to use some of the best practices and tools for web development.
Let's get started!
Before you can deploy your web application with Aptible, you need to create an app and configure your environment variables. An app is a logical unit of deployment in Aptible that represents your web application. Environment variables are key-value pairs that store configuration settings for your app, such as database credentials, API keys, etc.
You can use either the Aptible CLI or the Aptible dashboard to create an app and configure your environment variables. In this article, we will use the Aptible CLI, which is a command-line tool that allows you to interact with Aptible.
To create an app with the Aptible CLI, you need to:
Log in to your Aptible account using the aptible login
command. You will be prompted to enter your email and password, and then a verification code sent to your email.
Choose an environment for your app using the aptible switch
command. An environment is a logical grouping of resources in Aptible, such as apps, databases, and endpoints. You can have multiple environments for different purposes, such as development, staging, or production. In this article, we will use the production
environment, which is created by default when you sign up for Aptible.
Create an app using the aptible apps:create
command. You need to provide a name for your app, which must be unique within your environment. In this article, we will name our app web-app.
Please you can use any name other than “web-app"
Here is an example of the commands to create an app with the Aptible CLI:
$ aptible login
Email: [email protected]
Password: ********
Verification code: 123456
Logged in as [email protected]
$ aptible switch production
Switched to production
$ aptible apps:create web-app
App web-app created!
To configure your environment variables with the Aptible CLI, you need to:
- List the existing environment variables for your app using the aptible config
command. You will see some default environment variables that are set by Aptible, such as APTIBLE_APP_ID
, APTIBLE_APP_HANDLE
, etc.
- Add new environment variables for your app using the aptible config:set
command. You need to provide the key and value for each environment variable, separated by a space. You can add multiple environment variables at once by separating them with a space as well. In this article, we will add some environment variables that are required by our web application, such as DATABASE_URL
, SECRET_KEY_BASE
, RAILS_ENV
, etc.
- Verify that your environment variables are set correctly using the aptible config
command again.
Here is an example of the commands to configure your environment variables with the Aptible CLI:
$ aptible config --app web-app
APTIBLE_APP_ID=123
APTIBLE_APP_HANDLE=web-app
...
$ aptible config:set --app web-app
DATABASE_URL=postgres://user:password@host:port/db SECRET_KEY_BASE=abcdefg
RAILS_ENV=production
DATABASE_URL=postgres://user:password@host:port/db
SECRET_KEY_BASE=abcdefg
RAILS_ENV=production
$ aptible config --app web-app
APTIBLE_APP_ID=123
APTIBLE_APP_HANDLE=web-app
DATABASE_URL=postgres://user:password@host:port/db
SECRET_KEY_BASE=abcdefg
RAILS_ENV=production
...
You have now created an app and configured your environment variables with Aptible.
Next, you need to build and push your web application image to a container registry. A web application image is a file that contains all the code, dependencies, and configuration of your web application. A container registry is a service that stores and distributes your web application images.
You can use Docker or any other similar tool to build your web application image and tag it with a version number. Docker is a software that allows you to create, run, and share containers. A container is an isolated environment that runs your web application image. You can install Docker here.
To build your web application image with Docker, you need to:
- Navigate to the directory where your web application codebase and Dockerfile are located using the cd
command.
- Build your web application image using the docker build
command. You need to provide a name and a tag for your image, which must be unique within your container registry. The name and tag are separated by a colon (:
). In this article, we will name our image web-app
and tag it with v1
.
- Verify that your web application image is built correctly using the docker images
command. You will see your image listed along with its name, tag, size, and creation date.
Here is an example of the commands to build your web application image with Docker:
$ cd web-app
$ docker build -t web-app:v1 .
Sending build context to Docker daemon 2.048kB
Step 1/8 : FROM ruby:2.7
...
Successfully built 123456789abc
Successfully tagged web-app:v1
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web-app v1 123456789abc 10 seconds ago 1.23GB
To push your web application image to a container registry, you need to:
- Log in to your container registry account using the docker login
command. You will be prompted to enter your username and password, and then a verification code if required.
- Push your web application image using the docker push
command. You need to provide the name and tag of your image, as well as the name of your container registry. The name of your container registry is usually prefixed to the name of your image, separated by a slash (/
). In this article, we will use Docker Hub as our container registry, which is a public service that hosts and distributes Docker images. We will prefix our image name with our Docker Hub username, which is user
.
- Verify that your web application image is pushed correctly using the docker images
command again. You will see a message indicating that your image was pushed successfully.
Here is an example of the commands to push your web application image to Docker Hub:
$ docker login
Username: user
Password: ********
Verification code: 123456
Login Succeeded
$ docker push user/web-app:v1
The push refers to repository
[docker.io/user/web-app]
...
123456789abc: Pushed
v1: digest: sha256:abcdefg size: 1234
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
user/web-app v1 123456789abc 10 seconds ago 1.23GB
Alternatively, you can use another container registry of your choice, such as Google Container Registry (GCR), Amazon Elastic Container Registry (ECR), Microsoft Azure Container Registry (ACR), etc. Each container registry may have different requirements and steps for logging in, pushing, and pulling images. You can refer to their respective documentation for more details.
You have now built and pushed your web application image to a container registry.
After you have pushed your web application image to a container registry, you need to create a Kubernetes deployment and service for your web application. A deployment is an object that manages the creation and update of your pods, which are the smallest unit of deployment in Kubernetes. A service is an object that defines a logical set of pods and a policy to access them, such as load balancing, service discovery, etc.
You can use YAML files to define your Kubernetes deployment and service objects for your web application. YAML is a human-readable data format that allows you to specify the configuration and properties of your Kubernetes objects. You can use any text editor to create and edit YAML files.
To define your Kubernetes deployment object with a YAML file, you need to:
- Create a file with a .yaml
or .yml
extension, such as deployment.yaml
.
- Specify the apiVersion
, kind
, metadata
, and spec
fields for your deployment object.
These fields are required for any Kubernetes object:
The apiVersion
field indicates the version of the Kubernetes API that you are using. In this article, we will use apps/v1
, which is the latest stable version for deployments.
The kind
field indicates the type of the Kubernetes object. In this case, it is Deployment
.
The metadata
field contains information about the name, labels, annotations, etc. of your deployment object. Labels are key-value pairs that can be used to identify and group your Kubernetes objects. Annotations are key-value pairs that can be used to store additional information or metadata about your Kubernetes objects.
The spec
field contains the desired state and behavior of your deployment object, such as the number of replicas, the pod template, the update strategy, etc.
Specify the selector
, template
, and eplicas
fields within the spec
field for your deployment object. These fields are required for any deployment object.
The selector
field defines how to select the pods that belong to your deployment object. You need to provide a matchLabels
field that contains one or more labels that match the labels of your pods.
The emplate
field defines the pod template that will be used to create new pods for your deployment object. You need to provide a metadata
field that contains the labels of your pods, and a spec
field that contains the configuration and properties of your pods, such as the containers, volumes, environment variables, etc.
The replicas
field defines the number of pods that you want to run for your deployment object. You can specify any positive integer value. In this article, we will use 3 replicas for our deployment object.
- Specify the containers
, image
, and ports
fields within the spec
field of the pod template for your deployment object.
These fields are required for any pod that runs a containerized application.
The containers
field defines one or more containers that will run in your pod. You need to provide a name and an image for each container. The name can be any string that identifies your container within your pod. The image is the name and tag of your web application image that you pushed to your container registry in the previous step. You need to prefix the image name with the name of your container registry, separated by a slash (/
). In this article, we will prefix our image name with our Docker Hub username, which is user
.
The image
field defines the name and tag of your web application image that you pushed to your container registry in the previous step. You need to prefix the image name with the name of your container registry, separated by a slash (/
).
- The ports
field defines one or more ports that will be exposed by your container. You need to provide a name and a containerPort for each port. The name can be any string that identifies your port within your container. The containerPort is the port number that your web application listens on within your container. In this article, we will use 3000 as our containerPort for our web application.
Here is an example of a YAML file that defines a Kubernetes deployment object for our web application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
labels:
app: web-app
spec:
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app-container
image: user/web-app:v1
ports:
- name: http
containerPort: 3000
replicas:3
To define your Kubernetes service object with a YAML file, you need to:
- Create a file with a .yaml
or .yml
extension, such as service.yaml
.
- Specify the apiVersion
, kind
, metadata
, and spec
fields for your service object. These fields are required for any Kubernetes object.
• The mapiVersion
field indicates the version of the Kubernetes API that you are using. In this article, we will use v1
, which is the latest stable version for services.
• The kind
field indicates the type of the Kubernetes object. In this case, it is Service
.
• The metadata
field contains information about the name, labels, annotations, etc. of your service object. Labels are key-value pairs that can be used to identify and group your Kubernetes objects. Annotations are key-value pairs that can be used to store additional information or metadata about your Kubernetes objects.
• The spec
field contains the desired state and behavior of your service object, such as the type, ports, selector, etc.
- Specify the type
, ports
, and selector
fields within the spec
field for your service object. These fields are required for any service object.
• The type
field defines the type of your service object, which determines how your service will be exposed to the outside world. There are four types of services: ClusterIP, NodePort, LoadBalancer, and ExternalName. In this article, we will use ClusterIP as our service type, which is the default type that creates a virtual IP address within the cluster that can be used to access your pods.
• The ports
field defines one or more ports that will be exposed by your service. You need to provide a name, a port, and a targetPort for each port. The name can be any string that identifies your port within your service. The port is the port number that your service will expose to the outside world. The targetPort is the port number that your service will forward the traffic to within your pod. In this article, we will use 80 as our port and 3000 as our targetPort for our web application.
• The selector
field defines how to select the pods that belong to your service object. You need to provide one or more labels that match the labels of your pods.
Here is an example of a YAML file that defines a Kubernetes service object for our web application:
apiVersion: v1
kind: Service
metadata:
name: web-app-service
labels:
app: web-app
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 3000
selector:
app: web-app
To apply your YAML files to your Kubernetes cluster, you need to use kubectl
.
To apply your YAML files with kubectl, you need to:
- Navigate to the directory where your YAML files are located using the cd
command.
- Apply your YAML files using the kubectl apply
command. You need to provide the name of your YAML file or a directory that contains multiple YAML files as an argument. You can also use the -f
flag to specify the file or directory name. In this article, we will use a directory named k8s
that contains our YAML files for our deployment and service objects.
- Verify that your deployment and service objects are created correctly using the kubectl get
command. You can provide the name of your object or a type of object as an argument. You can also use the -o wide
flag to get more details about your objects.
Here is an example of the commands to apply and verify our YAML files with kubectl:
$ cd k8s
$ kubectl apply -f .
deployment.apps/web-app-deployment created
$ kubectl get deployment web-app-deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web-app-deployment 3/3 3 3 10s web-app-container user/web-app:v1 app=web-app
$ kubectl get service web-app-service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
web-app-service ClusterIP 10.100.200.300 <none> 80/TCP 10s app=web-app
You have now created a Kubernetes deployment and service for your web application.
After you have created a Kubernetes service for your web application, you need to expose your web application service to the internet with Aptible endpoints. An endpoint is an object that defines an entry point for accessing your web application service from the outside world. Aptible provides features such as SSL encryption, custom domains, path routing, etc. for your endpoints.
You can use the Aptible CLI to create an endpoint for your web application service.
To create an endpoint with the Aptible CLI, you need to:
- Create an endpoint using the aptible endpoints:create
command. You need to provide a name for your endpoint, which must be unique within your environment. You also need to provide some options for your endpoint, such as the protocol, port, hostname, path, etc.
• The --type
option defines the type of your endpoint, which determines how your endpoint will be exposed to the outside world. There are two types of endpoints: TCP and HTTPS. In this article, we will use HTTPS as our endpoint type, which is the default type that creates a secure and encrypted connection between your web application service and your clients.
• The --internal
option defines whether your endpoint will be internal or external. An internal endpoint can only be accessed from within your Aptible environment, while an external endpoint can be accessed from anywhere on the internet. In this article, we will use an external endpoint, which is the default option.
• The --port
option defines the port number that your endpoint will listen on. You need to provide a port number that matches the port number that your web application service exposes. In this article, we will use 80 as our port number for our web application service.
• The --hostname
option defines the hostname that your endpoint will use. You can provide a custom domain name that you own and have configured with DNS records, or use a default domain name that is provided by Aptible. In this article, we will use a custom domain name that we own and have configured with DNS records, which is web-app.example.com.
If you don't want to buy a custom domain name, please note that Aptible will give you a free subdomain that you can use for your application and you can change it later to a custom domain anytime you want.
• The --path
option defines the path that your endpoint will use. You can provide a specific path that you want to route to your web application service, or use a wildcard path that matches any path. In this article, we will use a wildcard path that matches any path, which is /
.
- Verify that your endpoint is created correctly using the aptible endpoints:list
command. You will see your endpoint listed along with its name, type, internal flag, port, hostname, path, etc.
Here is an example of the commands to create an endpoint with the Aptible CLI:
$ aptible switch production
Switched to production
$ aptible endpoints:create --type https --internal false --port 80 --hostname web-app.example.com --path / web-app
Endpoint web-app created!
$ aptible endpoints:list --app web-app
NAME TYPE INTERNAL PORT HOSTNAME PATH
web-app HTTPS false 80 web-app.example.com /
Aptible will automatically provide and manage SSL certificates for your endpoint using Let's Encrypt, which is a free and open certificate authority that provides domain validation certificates. You do not need to do anything to enable SSL encryption for your endpoint. However, you need to make sure that your custom domain name is configured with DNS records that point to your Aptible environment. You can find the DNS records for your environment on the Aptible dashboard under the Domains tab.
You have now exposed your web application service to the internet with Aptible endpoints.
After you have exposed your web application service to the internet with Aptible endpoints, you need to test and verify your web application deployment. You can use curl
to send requests to your web application endpoint and check the responses. You can also use kubectl
to monitor the status and logs of your web application pods and service.
You can use curl to send requests to your web application endpoint and check the responses. Curl is a command-line tool that allows you to transfer data from or to a server using various protocols, such as HTTP, HTTPS, FTP, etc.
To send requests to your web application endpoint with curl, you need to:
- Use the curl
command with the URL of your web application endpoint as an argument. The URL is composed of the protocol, hostname, and path of your endpoint. In this article, we will use https://web-app.example.com/
as our URL for our web application endpoint.
- Check the output of the curl command on the terminal window. You will see the status code, headers, and body of the response from your web application endpoint. The status code indicates the result of your request, such as 200 for success, 404 for not found, 500 for internal server error, etc. The headers contain information about the server, content type, date, etc. The body contains the actual content of the response, such as HTML, JSON, XML, etc.
Here is an example of how to send requests to your web application endpoint with curl:
$ curl https://web-app.example.com/
HTTP/1.1 200 OK
Server: nginx/1.19.10
Date: Tue, 10 Oct 2023 19:19:51 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1234
Connection: keep-alive
X-Powered-By: Aptible
<html>
<head>
<title>Web App</title>
</head>
<body>
<h1>Welcome to Web App!</h1>
<p>This is a sample web application deployed with Aptible and Kubernetes.</p>
</body>
</html>
You can also use kubectl to monitor the status and logs of your web application pods and service. Kubectl is a command-line tool that allows you to interact with your Kubernetes cluster. You can install kubectl here.
To monitor the status of your web application pods and service with kubectl, you need to:
- Open a terminal window on your computer.
- Use the kubectl get
command with the name or type of your object as an argument. You can also use the `-o wide` flag to get more details about your object, such as the node name, pod IP, labels, etc.
- Check the output of the kubectl get command on the terminal window. You will see information about your object, such as the name, ready state, up-to-date state, available state, age, etc.
Here is an example of how to monitor the status of your web application pods and service with kubectl:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-app-deployment-f4c6d9b4f-4jw9m 1/1 Running 0 5m23s 10.100.200.301 node-1 <none> <none>
web-app-deployment-f4c6d9b4f-hx7kq 1/1 Running 0 5m23s 10.100.200.302 node-2 <none> <none>
web-app-deployment-f4c6d9b4f-z9v7n 1/1 Running 0 5m23s 10.100.200.303 node-3 <none> <none>
$ kubectl get service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
web-app-service ClusterIP 10.100.200.300 <none> 80/TCP 5m23s app=web-app
To monitor the logs of your web application pods with kubectl, you need to:
- Open a terminal window on your computer.
- Use the kubectl logs
command with the name of your pod as an argument. You can also use the -f
flag to follow the logs in real time, or the --since
flag to specify a time range for the logs.
- Check the output of the kubectl logs command on the terminal window. You will see the logs of your pod, which contain the messages and errors from your web application container.
Here is an example of how to monitor the logs of your web application pods with kubectl:
$ kubectl logs web-app-deployment-f4c6d9b4f-4jw9m -f --since=10m
[2023-10-10 19:19:51] INFO WEBrick 1.6.0
[2023-10-10 19:19:51] INFO ruby 2.7.0 (2019-12-25) [x86_64-linux]
[2023-10-10 19:19:51] INFO WEBrick::HTTPServer#start: pid=1 port=3000
I, [2023-10-10T19:20:12.345678 #1] INFO -- : Started GET "/" for 10.100.200.400 at 2023-10-10 19:20:12 +0000
I, [2023-10-10T19:20:12.456789 #1] INFO -- : Processing by HomeController#index as HTML
I, [2023-10-10T19:20:12.567890 #1] INFO -- : Rendering home/index.html.erb within layouts/application
I, [2023-10-10T19:20:12.678901 #1] INFO -- : Rendered home/index.html.erb within layouts/application (Duration: 11.0ms | Allocations: 1234)
I, [2023-10-10T19:20:12.789012 #1] INFO -- : Completed 200 OK in 33ms (Views: 22.0ms | ActiveRecord: 0.0ms | Allocations: 4567)
You have now tested and verified your web application deployment with Aptible and Kubernetes. You have learned how to use some of the best practices and tools for web development, such as Aptible, Kubernetes, Docker, curl, kubectl, etc.
Congratulations! You have successfully deployed a scalable web application with Aptible and Kubernetes!
In this article, you have learned how to deploy a scalable web application with Aptible and Kubernetes. You have followed these steps:
- Create an Aptible app and configure your environment variables
- Build and push your web application image to a container registry
- Create a Kubernetes deployment and service for your web application
- Expose your web application service to the internet with Aptible endpoints
- Test and verify your web application deployment
By following these steps, you have achieved these outcomes:
- You have created a secure and compliant environment for your web application with Aptible
- You have orchestrated the deployment and scaling of your web application across multiple nodes with Kubernetes
- You have exposed your web application to the internet with SSL encryption, custom domains, path routing, etc. with Aptible
- You have tested and verified your web application using curl and kubectl
Here are some tips and best practices for deploying a scalable web application with Aptible and Kubernetes:
- Use health checks to monitor the readiness and liveness of your pods and containers. Health checks are probes that can be configured to check the status of your pods and containers at regular intervals. If a pod or container fails a health check, Kubernetes will restart or replace it automatically. You can learn how to configure health checks here.
- Use rolling updates to update your pods and containers without downtime. Rolling updates are a strategy that can be configured to update your pods and containers gradually, one by one, while maintaining the availability of your service.
- Use autoscaling to adjust the number of pods and nodes according to the load of your service. Autoscaling is a feature that can be configured to scale your pods and nodes up or down automatically, based on the CPU utilization, memory usage, or custom metrics of your service.
Read Also:
How to Optimize Your CI/CD Pipeline for Maximum Efficiency
How to Monitor Your Kubernetes Cluster with Prometheus and Grafana
I hope you enjoyed this article and learned something new. Happy Deployment!