Backup and restore a Postgres database

Introduction

In this tutorial, How to backup and restore a Postgres database. You have installed the PostgreSQL database system.

Why Backup Your PostgreSQL Database?

Before we dive into the how, let’s briefly discuss the importance of regular database backups:

  • Data Loss Prevention: Backups protect your data against accidental deletion, corruption, or hardware failures.
  • Disaster Recovery: In the event of a catastrophic failure or data breach, having a backup allows you to quickly recover and restore your database.
  • Testing and Development: Backups can be used to create copies of your database for testing, development, or staging purposes.

Now, let’s get started with the backup and restore process.

Backup and restore a Postgres database

Backup a PostgreSQL Database

The pg_dump command is the PostgreSQL utility for creating database backups. Here’s the basic syntax:

pg_dump -U your_postgres_user -d your_database_name -f backup_file.sql

For example: import and export my-db database as below

The output format is a plain-text SQL script file ( The default)

root@5cc6d8f56baf:/# pg_dump -h localhost -U devopsroles my-db > my-db.sql

You can compress this data by using the “custom” dump format:

# format tar
root@5cc6d8f56baf:/# pg_dump -h localhost -U devopsroles -F t my-db > my-db.tar

Backup use pg_dump via a compression tool such as gzip

root@5cc6d8f56baf:/# pg_dump -h localhost -U devopsroles my-db | gzip > my-db.gz

Backup Remote PostgreSQL Databases

pg_dump -U devopsroles -h 192.168.1.122 -p 5432 my-db > my-db.sql

To explain:

  • -U: to specify the database role name
  • -h: remote host
  • -p: port a PostgreSQL database

To back up all PostgreSQL databases

root@5cc6d8f56baf:/# pg_dumpall -h localhost -U devopsroles > all_pg_dbs.sql

Restore the dump using the psql command

pgsql -f all_pg_dbs.sql postgres

Restoring a PostgreSQL Database

You can use psql or pg_restore utilities for retore postgres databases.

For example:

root@5cc6d8f56baf:/# psql -h localhost -U devopsroles my-db < my-db.sql
root@5cc6d8f56baf:/# pg_restore -h localhost -U devopsroles -d my-db my-db.tar

Conclusion

egularly backing up and, if necessary, restoring your PostgreSQL database is essential for data protection and disaster recovery. Remember to schedule automated backups, keep your backup files in a secure location, and test your backup and restore procedures periodically to ensure they work as expected.

By following these steps, you can safeguard your data and have peace of mind knowing that your PostgreSQL database is protected against data loss and system failures.

You have Backup and restore a Postgres database. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Docker run PostgreSQL: A Step-by-Step Guide

Introduction

In today’s fast-paced development environments, the ability to quickly deploy and manage databases is crucial. Docker provides a powerful solution for running PostgreSQL databases in isolated containers, making it easier to develop, test, and deploy your applications. In this tutorial, you will learn how to use Docker run PostgreSQL databases and connect to them, enabling you to efficiently manage your database environments with minimal setup. Whether you’re new to Docker or looking to streamline your database management, this guide will equip you with the essential knowledge to get started.

  • PostgreSQL is a powerful, open-source object-relational database
  • Docker is an open platform that runs an application in an isolated environment called a container.

Prerequisites

Docker Run PostgreSQL container

You have to use Docker to run PostgreSQL databases. Below is an example command to run a PostgreSQL container:

docker run --name my-postgres-db -p 9000:5432 -e POSTGRES_PASSWORD=123456789  -e POSTGRES_USER=devopsroles  -e POSTGRES_DB=my-db -d postgres:14

Note:

  • -p 9000:5432: Host port 9000 and Container port 5432
  • Image: postgres version 14
  • Container name: my-postgres-db
  • Environment variables to configure our database: POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB

The output terminal is below

Using psql command to connect the database

psql --host localhost --port 5432 --username devopsroles --dbname my-db

The output terminal is below

Your database is currently empty. I will create a table as an example

CREATE TABLE sites (id SERIAL PRIMARY KEY, name VARCHAR(100));
INSERT INTO sites (name)
  VALUES ('devopsroles.com'), ('huuphan.com');

I will run a command to query the table created.

SELECT * FROM sites;

The output terminal is below

Docker Manage data persistence

The problem is that we stop and start the container with the commands “docker stop my-postgres-db” and “docker start my-postgres-db” when creating a new container will not allow us to access the database that you are created, as it was isolated in your container.

Create a new volume with the following command. The solution stores the database outside of the container

docker volume create my-postgres-db-db

You will stop and remove your current container and create a new one.

docker stop my-postgres-db
docker rm my-postgres-db
docker run --name my-postgres-db -p 5432:5432  -e POSTGRES_PASSWORD=123456789  -e POSTGRES_USER=devopsroles  -e POSTGRES_DB=my-db -v my-postgres-db-db:/var/lib/postgresql/data -d postgres:14

How to know where the database is stored on your computer

docker inspect my-postgres-db-db

The output terminal is below

Conclusion

Using Docker to run PostgreSQL databases offers a streamlined approach to managing your database environments with ease and efficiency. I hope this tutorial has provided you with the necessary insights and steps to confidently set up and connect to PostgreSQL using Docker. Thank you for reading the  DevopsRoles page and I hope this guide proves helpful in your journey toward optimizing your development and deployment processes.

How to delete docker image with dependent child images

As experienced DevOps engineers, we often treat Docker image cleanup as a routine garbage collection task. However, the Docker daemon occasionally halts this process with a specific conflict error that prevents the removal of an image ID. If you have attempted to remove a base image and encountered the error conflict: unable to delete [IMAGE_ID] (cannot be forced) - image has dependent child images, you are dealing with Docker’s layered filesystem architecture in action.

This guide dives into the mechanics of UnionFS layers to explain why this happens and provides production-ready strategies to delete docker image with dependent child images safely and effectively.

Understanding the “Dependent Child Images” Error

To fix the problem, we must first respect the underlying architecture. Docker images are not monolithic files; they are a stack of read-only layers. When you build Image B using FROM Image A, Image B becomes a “child” of Image A. Docker uses storage drivers (like overlay2) to reference the layers of the parent image rather than duplicating them.

The error occurs because deleting the parent image (Image A) would render the child image (Image B) corrupt, as its base layers would vanish from the filesystem.

Technical Context: Unlike a running container conflict—which blocks deletion because a read-write layer is active—a dependent child conflict is purely about filesystem integrity. The Docker daemon protects the Directed Acyclic Graph (DAG) of your image layers.

Today, I can’t delete docker images with dependent child images. How to delete docker image with dependent child images.

I want to delete image e16184e8dd39

[vagrant@localhost docker-flask-app]$ docker images
REPOSITORY             TAG       IMAGE ID       CREATED        SIZE
python                 3.6       e16184e8dd39   9 days ago     902MB
mysql                  5.7       938b57d64674   2 weeks ago    448MB
docker-flask-app_app   latest    44ae2f35ec29   3 weeks ago    915MB
<none>                 <none>    0e0359a5ec25   3 weeks ago    908MB
<none>                 <none>    3a59efe32b9c   3 weeks ago    908MB
postgres               latest    6ce504119cc8   5 weeks ago    374MB
odoo                   14        4f53998176ca   5 weeks ago    1.41GB
postgres               <none>    346c7820a8fb   2 months ago   315MB

I am trying with command as below

sudo docker rmi e16184e8dd39

Error delete docker image with dependent child images

[vagrant@localhost docker-flask-app]$ sudo docker rmi e16184e8dd39
Error response from daemon: conflict: unable to delete e16184e8dd39 (cannot be forced) - image has dependent child images
[vagrant@localhost docker-flask-app]$

I can not delete an image with the -f flag.

How to Fixed it

You should try to remove unnecessary images before removing the image:

[vagrant@localhost docker-flask-app]$ docker rmi $(docker images -q) -f

The output terminal as below

Note: This command above will remove images all.

After you remove the image.

docker rmi -f e16184e8dd39

Expert Troubleshooting: Why `docker rmi` Still Fails

Sometimes, even after following the steps above to delete docker image with dependent child images, the daemon persists with errors. Here are the edge cases:

  • Stopped Containers: A stopped container still holds a reference to the image. Ensure you run docker ps -a to catch exited containers.
  • Build Cache: Modern Docker BuildKit uses a separate cache. If you are seeing space usage issues not resolved by rmi, you may need to prune the build cache specifically.
docker builder prune

For a deeper understanding of how Docker manages storage and references, consult the official Docker Storage Driver documentation.

Frequently Asked Questions (FAQ)

What is the difference between a dependent child image and a container?

A container is a runtime instance of an image (a read-write layer on top). A dependent child image is a separate static image that was built FROM the parent image. docker rm handles containers, while docker rmi handles images.

Why do I see so many <none> images?

These are usually dangling images (layers that have no relationship to any tagged images) or intermediate layers. They frequently cause dependency errors when you try to delete their parents. Using docker image prune is the standard maintenance procedure for this.

Is it safe to delete the /var/lib/docker folder directly?

This is the “nuclear option” and should be avoided unless the daemon is completely corrupted. Manually deleting files in /var/lib/docker bypasses the Docker daemon’s database, which can lead to inconsistent states and require a full reinstall of the Docker engine.

Conclusion

Managing the lifecycle of container artifacts is a core competency for any DevOps engineer. The error regarding dependent child images is a safety mechanism, ensuring that the shared layers required by your ecosystem remain intact.

To successfully delete docker image with dependent child images, prioritize identifying the child image using docker inspect. Use force flags judiciously, and lean on docker system prune for maintaining hygiene in your build environments. By understanding the parent-child relationship in UnionFS, you can keep your registry clean without breaking production dependencies . Thank you for reading the DevopsRoles page!

Docker setup Nginx Flask and Postgres

Introduction

In this tutorial, How to use Docker setup Nginx Flask and Postgres.

Prerequisites

Docker setup Nginx Flask and Postgres

The structure folder and file of the app.

Nginx

The first Docker Nginx. It will be used as a proxy server.

User --> Nginx --> Python application

Dockerfile file

[vagrant@localhost nginx-flask-postgres]$ cat nginx/Dockerfile
FROM nginx:latest

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/devopsroles.conf /etc/nginx/conf.d/

Example devopsroles.conf file

server {
  listen 80;
  server_name _;

  location / {
    try_files $uri @app;
  }

  location @app {
    include /etc/nginx/uwsgi_params;
    uwsgi_pass flask:8080;
  }
}

Flask

The second Docker container Python application running on a uWSGI server.

Dockerfile file

[vagrant@localhost nginx-flask-postgres]$ cat nginx/Dockerfile
FROM nginx:latest

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/devopsroles.conf /etc/nginx/conf.d/
[vagrant@localhost nginx-flask-postgres]$ cat flask/Dockerfile
# Base Image
FROM python:3.6-alpine as BASE

RUN apk add --no-cache linux-headers g++ postgresql-dev gcc build-base linux-headers ca-certificates python3-dev libffi-dev libressl-dev libxslt-dev
RUN pip wheel --wheel-dir=/root/wheels psycopg2
RUN pip wheel --wheel-dir=/root/wheels cryptography

# Actual Image
FROM python:3.6-alpine as RELEASE

EXPOSE 8080
WORKDIR /app

ENV POSTGRES_USER="" POSTGRES_PASSWORD="" POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=""

COPY dist/ ./dist/
COPY flask/uwsgi.ini ./
COPY --from=BASE /root/wheels /root/wheels

RUN apk add --no-cache build-base linux-headers postgresql-dev pcre-dev libpq uwsgi-python3 && \
    pip install --no-index --find-links=/root/wheels /root/wheels/* && \
    pip install dist/*

CMD ["uwsgi", "--ini", "/app/uwsgi.ini"]

Note:

  • It exposes port 8080
  • creates a default directory /app/

uwsgi.ini file

[uwsgi]
socket = :8080
module = devopsroles.wsgi:app
master = 1
processes = 4
plugin = python

Postgres

Get Postgres the latest Postgres image from Docker Hub. Then we pass environment variables to it.

Example: database.conf file

[vagrant@localhost nginx-flask-postgres]$ cat postgres/database.conf
POSTGRES_USER=test
POSTGRES_PASSWORD=password
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=devopsroles

The final docker-compose.yml

[vagrant@localhost nginx-flask-postgres]$ pwd
/home/vagrant/nginx-flask-postgres
[vagrant@localhost nginx-flask-postgres]$ cat docker-compose.yml
version: '3.5'

services:
  web_server:
    container_name: nginx
    build:
      context: .
      dockerfile: nginx/Dockerfile
    ports:
      - 80:80
    depends_on:
      - app

  app:
    container_name: flask
    build:
      context: .
      dockerfile: flask/Dockerfile
    env_file: postgres/database.conf
    expose:
      - 8080
    depends_on:
      - database

  database:
    container_name: postgres
    image: postgres:latest
    env_file: postgres/database.conf
    ports:
      - 5432:5432
    volumes:
      - db_volume:/var/lib/postgresql

volumes:
  db_volume:

Docker Compose Build and Run

docker-compose up --build -d

The result Docker container Nginx, Flask, and Postgres

Conclusion

You have Deploy Docker setup Nginx Flask and Postgres. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Deploy Flask-MySQL app with docker-compose

Introduction

In this tutorial, How to deploy Flask-MySQL app with docker-compose. From the official docs. Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. The fist, You need to install Docker and docker-compose. Next, we will Deploy Flask-MySQL app.

The folder and file structure of the app

[vagrant@localhost ~]$ tree docker-flask-app
docker-flask-app
├── app
│   ├── app.py
│   ├── Dockerfile
│   └── requirements.txt
├── db
│   └── init.sql
└── docker-compose.yml

2 directories, 5 files
[vagrant@localhost ~]$
  • File app.py is the Flask app which connect to database and exposes on REST API endpoint.
  • init.sql an SQL script to initialize the database before run app.

The content of app.py and init.sql as below

[vagrant@localhost docker-flask-app]$ cat app/app.py
from typing import List, Dict
from flask import Flask
import mysql.connector
import json

app = Flask(__name__)

def test_table() -> List[Dict]:
    config = {
        'user': 'root',
        'password': 'root',
        'host': 'db',
        'port': '3306',
        'database': 'devopsroles'
    }
    connection = mysql.connector.connect(**config)
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM test_table')
    results = [{name: color} for (name, color) in cursor]
    cursor.close()
    connection.close()

    return results


@app.route('/')
def index() -> str:
    return json.dumps({'test_table': test_table()})


if __name__ == '__main__':
    app.run(host='0.0.0.0')
[vagrant@localhost docker-flask-app]$ cat db/init.sql
create database devopsroles;
use devopsroles;

CREATE TABLE test_table (
  name VARCHAR(20),
  color VARCHAR(10)
);

INSERT INTO test_table
  (name, color)
VALUES
  ('dev', 'blue'),
  ('pro', 'yellow');

Create a Docker image for Flask app

Create a Dockerfile file in the app folder.

[vagrant@localhost docker-flask-app]$ cat app/Dockerfile
# Use an official Python runtime as an image
FROM python:3.6

# The EXPOSE instruction indicates the ports on which a container
EXPOSE 5000

# Sets the working directory for following COPY and CMD instructions
# Notice we haven’t created a directory by this name - this instruction
# creates a directory with this name if it doesn’t exist
WORKDIR /app

COPY requirements.txt /app
RUN python -m pip install --upgrade pip
RUN pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host=files.pythonhosted.org --no-cache-dir -r requirements.txt

# Run app.py when the container launches
COPY app.py /app
CMD python app.py

You need dependencies Flask and mysql-connector in File requirements.txt

[vagrant@localhost docker-flask-app]$ cat app/requirements.txt
flask
mysql-connector

Create a docker-compose.yml

[vagrant@localhost docker-flask-app]$ cat docker-compose.yml
version: "2"
services:
  app:
    build: ./app
    links:
      - db
    ports:
      - "5000:5000"
  db:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - ./db:/docker-entrypoint-initdb.d/:ro

Running the Flask app

[vagrant@localhost docker-flask-app]$ docker-compose up -d

The result, after running the Flask app

FAQs

1. What is Docker-Compose?

Docker-Compose is a tool for defining and running multi-container Docker applications. It allows you to configure your application’s services in a YAML file and start all services with a single command.

2. How can I persist data in MySQL?

In the Docker-Compose file, the db_data volume ensures that the data in MySQL is persisted even if the container is stopped.

3. Can I use a different database with Flask?

Yes, Flask can work with various databases like PostgreSQL, SQLite, and more. You need to adjust the connection setup in your Flask app and Docker-Compose file accordingly.

Conclusion

You have Deploy Flask-MySQL app with docker-compose. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Mastering the Power of xargs Command for your work

Introduction

xargs Command powerful tool that can revolutionize the way you handle various tasks on your system. Whether it’s processing files, executing commands in parallel, or manipulating data streams, xargs is a versatile Swiss Army knife for any Linux enthusiast.

What does the xargs command in Linux?

xargs is a great command that reads streams of data from standard input, then generates and executes command lines.

In this blog, we will explore the ins and outs of the xargs command, its practical applications, and how it can make your life as a Linux user much easier.

Syntax

xargs [options] [command]

Here are some common options used with the xargs command:

  • -n: Specifies the maximum number of items to be passed as arguments to the command.
  • -I: Allows you to specify a placeholder (usually {}) for the argument, which is replaced by each item from the input.
  • -t: Prints the command being executed before running it.
  • -p: Asks for confirmation before executing each command.
  • -r: Prevents the command from running if there is no input.
  • -a: Specifies the input file from which xargs should read the items instead of STDIN.
  • -P: Sets the maximum number of parallel processes to run at once.

xargs command Tips and Tricks

How to create multiple files with xargs command in Linux.

echo devopsrolesfile1 devopsrolesfile2 devopsrolesfile3 | xargs touch

The output terminal is below

Creates a file with blanks in its name

echo 'my new file devopsroles' | xargs -d '\n' touch

The output terminal is below

Changes permissions on all PNG files within the /home/vagrant directory

find /home/vagrant -name "*.png" -type f | xargs chmod 640

To view the command that is run by xargs, add the -t option:

echo devopsrolesfile1 devopsrolesfile2 devopsrolesfile3 | xargs -t touch

We use find to locate files that haven’t been updated in more than four weeks and xargs to remove them.

find . -mtime +29 | xargs rm

finding and removing empty files

find . -size 0 | xargs rm
# or
find . -size 0 | xargs -I{} rm -v {}

How to count the characters in each file.

ls -Srp | grep -v '/$' | xargs -I X wc -c X

The output terminal as below

Check the most recent four logins for each currently logged-in user.

who | awk '{print $1}' | xargs -I x last -4 x

The output terminal is below

Conclusion

You have to use xargs command for your work daily. The xargs command is an indispensable tool that empowers Linux users to streamline their tasks and increase productivity.

The xargs command is a versatile tool that can greatly enhance your command-line productivity. Whether you’re processing files, running commands in parallel, or performing batch operations, xargs can simplify and automate many tasks. However, it’s important to use it with care, especially when dealing with commands that modify or delete files.

Its ability to handle large sets of data, parallelize operations, and simplify complex tasks makes it a valuable asset in any Linux user’s toolkit. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers in ASG with ELB

#Introduction

In this tutorial, How to deploy cluster web servers in Auto Scaling Group with ELB use Terraform.

What does Elastic Load Balancer mean?

Elastic Load Balancer allows balancing the load across the nodes ASG cluster.ELB also helps to manage SSL cert if your project requires HTTPS access.

Three types of ELB: Classic Load Balancer, Network Load Balancer, and Application Load Balancer.

Auto Scaling Group: allow us to scale up and scaling down the resources based on usage.

Auto Scaling Policy: the key feature of Auto Scaling Group is to scale up or scale down resources based on Auto Scaling Policy we attach.

  • AWS auto scaling Group: Min = 2, Max = 10 and desired_capacity =3
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Auto Scaling Group: Scaling Policy – Target Tracking policy
  • Security group ingress rule to allow access web server from my laptop ? and ELB security group.
  • Elastic load balancer
  • Elastic load balancer security group: ingress rule to allow access web server from my laptop ?

Structure folder and files

Created Cluster_WebServer_ASG_ELB folder contains files as below:

asg_config.tf
auto_scale_group.tf
output.tf
provider.tf
securitygroups.tf
variables.tf
elastic_load_balancer.tf
elb_security_group.tf

On AWS

we created key pair terraform-demo as the picture below

Deploy cluster web servers in ASG with ELB

Create a new file asg_config.tf with the content as below

resource aws_launch_configuration "my_config" {
image_id = var.ami
instance_type = var.instance_type
security_groups=["${aws_security_group.web_sg.id}"]
key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
lifecycle {
create_before_destroy = true
}
}

Create a new file auto_scale_group.tf with the content as below

resource "aws_autoscaling_group" "first_asg" {
	launch_configuration = aws_launch_configuration.my_config.id
	availability_zones = "${var.azs}"
    
	min_size = 2
	max_size = 10
	desired_capacity = 3
	tag {
		key = "Name"
		value = "terraform-asg"
		propagate_at_launch = true  
	}
}

New file elastic_load_balancer.tf with the content as below

resource "aws_elb" "first_elb" {
    name = "terraform-elb"
    availability_zones = var.azs
    security_groups=[ aws_security_group.elb_sg.id ]
    listener {
        lb_port=80
        lb_protocol ="http"
        instance_port = var.server_port
        instance_protocol= "http"
    }
    health_check {
        healthy_threshold = 2
        unhealthy_threshold = 2
        timeout=3
        interval = 30
        target = "HTTP:${var.server_port}/"
    }
}

Create a new file elb_security_group.tf with the content as below

resource "aws_security_group" "elb_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

Create a new file output.tf with the content as below

output "elb_endpoint" {
    value = [ "${aws_elb.first_elb.arn}"]
}

provider.tf file

provider "aws" {
        region = var.region
}

securitygroups.tf file

resource "aws_security_group" "web_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        security_groups = [ aws_security_group.elb_sg.id ]
    } 
       
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

variables.tf file

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
    description = "amazon machine image"
        default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
    default = [ "us-west-2a", "us-west-2b", "us-west-2c" ]
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

Applying a template

$ terraform apply

Conclusion

You have to deploy cluster web servers in ASG with ELB use Terraform. I hope will this your helpful. Thank you for reading the DevopsRoles page!

How to install Ansible by using Virtualenv

Introduction

In this tutorial, How to install Ansible by using virtualenv. You can test and deploy multiple Ansible versions with virtualenv.

Remember that you’ll need to activate the virtual environment every time you want to use Ansible within it.

Why Use Virtualenv with Ansible?

Using Virtualenv to install Ansible offers several benefits:

  • Isolation: Virtualenv creates an isolated environment for Ansible, preventing conflicts with system-wide Python packages.
  • Version Control: You can easily manage Ansible versions and dependencies for different projects by creating separate Virtualenv environments.
  • Cleaner Development: Virtualenv helps keep your system Python environment clean by separating Ansible and its dependencies.

Now, let’s dive into the installation process.

My lab

  • Host OS: Windows 10
  • Vagrant Box: ubuntu
  • Install Ansible on Ubuntu

Setting up Vagrant on Ubuntu Linux

Vagrant.configure("2") do |config|
config.ssh.insert_key = false
config.vm.provider :virtualbox do |vb|
  vb.memory = 1500
  vb.cpus = 2
end
# Application server 1.
config.vm.define "ubuntu" do |ubuntu|
  ubuntu.vm.hostname = "devopsroles.com"
  ubuntu.vm.box = "bento/ubuntu-21.04"
  ubuntu.vm.network :private_network, ip: "192.168.3.7"
  ubuntu.vm.network :forwarded_port, host: 4566, guest: 4566
  ubuntu.vm.network :forwarded_port, host: 8055, guest: 8080
end
end

Start and log into the Virtual Machine

vagrant up
vagrant ssh

The output terminal is as below

How to Install Ansible by using virtualenv

To install Ansible using a virtual environment (virtualenv), you can follow these steps:

RHEL/CentOS 7

sudo yum install python3-virtualenv

Ubuntu/Debian

sudo apt-get update
sudo apt-get install python3-virtualenv

Set up virtualenv and Install Ansible

You need to create a “virtual environment” to host your local copy of Ansible.

virtualenv ansible2.9

This command creates a directory called ansible2.9 in your current working directory.

You must activate it

source ansible2.9/bin/activate

You should see the prompt change to include the virtualenv name.

(ansible2.9) $

The output terminal is as below

Let’s install Ansible

pip3 install ansible==2.9

The output terminal is as below

Conclusion

Congratulations! You’ve successfully installed Ansible using Virtualenv. This setup allows you to manage Ansible and its dependencies separately, ensuring a clean and controlled environment for your automation tasks. Activate the virtual environment whenever you need to work with Ansible and deactivate it when you’re done to keep your system Python environment tidy. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers in Auto Scaling Group

#Introduction

In this tutorial, How to deploy cluster web servers use Terraform. Now, let’s go Terraform deploy cluster web servers in Auto Scaling Group

  • AWS auto scaling Group: Min = 2, Max = 10 and desired_capacity =3
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Auto Scaling Group: Scaling Policy – Target Tracking policy
  • Security group ingress rule to allow access web server from my laptop ?

Structure folder and files Terraform deploy cluster web servers in Auto Scaling Group

Created Cluster_WebServer_ASG folder contains files as below:

asg_config.tf
auto_scale_group.tf
auto_scale_policy.tf
output.tf
provider.tf
securitygroups.tf
variables.tf

On AWS

we created key pair terraform-demo as the picture below

Deploy cluster web servers in Auto Scaling Group

Create a new file asg_config.tf with the content as below

resource aws_launch_configuration "my_config" {
name = "webserver-launch"
image_id = var.ami
instance_type = var.instance_type
security_groups=["${aws_security_group.web_sg.id}"]
key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
}

Create a new file auto_scale_group.tf with the content as below

resource "aws_autoscaling_group" "first_asg" {
	launch_configuration = aws_launch_configuration.my_config.id
	availability_zones = "${var.azs}"
    
	min_size = 2
	max_size = 10
	desired_capacity = 3
	tag {
		key = "Name"
		value = "terraform-asg"
		propagate_at_launch = true  
	}
}

New file auto_scale_policy.tf with the content as below

resource "aws_autoscaling_policy" "my_asg_policy" {
  name = "webservers_autoscale_policy"
  policy_type = "TargetTrackingScaling"
  autoscaling_group_name = aws_autoscaling_group.first_asg.name

  target_tracking_configuration {
  predefined_metric_specification {
    predefined_metric_type = "ASGAverageCPUUtilization"
  }
  target_value = "75"
  }

}

Create new a provider.tf the content as below

provider "aws" {
        region = var.region
}

Create a new file output.tf with the content as below

output "asg_arn" {
    value = [ "${aws_autoscaling_group.first_asg.arn}"]
}

Create new file variables.tf with the content as below

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
    description = "amazon machine image"
        default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
    default = [ "us-west-2a", "us-west-2b", "us-west-2c" ]
}

new file securitygroups.tf with the content as below

resource "aws_security_group" "web_sg" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer_ASG>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_autoscaling_group.first_asg will be created
  + resource "aws_autoscaling_group" "first_asg" {
      + arn                       = (known after apply)
      + availability_zones        = [
          + "us-west-2a",
          + "us-west-2b",
          + "us-west-2c",
        ]
      + default_cooldown          = (known after apply)
      + desired_capacity          = 3
      + force_delete              = false
      + force_delete_warm_pool    = false
      + health_check_grace_period = 300
      + health_check_type         = (known after apply)
      + id                        = (known after apply)
      + launch_configuration      = (known after apply)
      + max_size                  = 10
      + metrics_granularity       = "1Minute"
      + min_size                  = 2
      + name                      = (known after apply)
      + name_prefix               = (known after apply)
      + protect_from_scale_in     = false
      + service_linked_role_arn   = (known after apply)
      + vpc_zone_identifier       = (known after apply)
      + wait_for_capacity_timeout = "10m"

      + tag {
          + key                 = "Name"
          + propagate_at_launch = true
          + value               = "terraform-asg"
        }
    }

  # aws_autoscaling_policy.my_asg_policy will be created
  + resource "aws_autoscaling_policy" "my_asg_policy" {
      + arn                     = (known after apply)
      + autoscaling_group_name  = (known after apply)
      + id                      = (known after apply)
      + metric_aggregation_type = (known after apply)
      + name                    = "webservers_autoscale_policy"
      + policy_type             = "TargetTrackingScaling"

      + target_tracking_configuration {
          + disable_scale_in = false
          + target_value     = 60

          + predefined_metric_specification {
              + predefined_metric_type = "ASGAverageCPUUtilization"
            }
        }
    }

  # aws_launch_configuration.my_config will be created
  + resource "aws_launch_configuration" "my_config" {
      + arn                         = (known after apply)
      + associate_public_ip_address = false
      + ebs_optimized               = (known after apply)
      + enable_monitoring           = true
      + id                          = (known after apply)
      + image_id                    = "ami-0c2d06d50ce30b442"
      + instance_type               = "t2.micro"
      + key_name                    = "terraform-demo"
      + name                        = "webserver-launch"
      + name_prefix                 = (known after apply)
      + security_groups             = (known after apply)
      + user_data                   = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + no_device             = (known after apply)
          + snapshot_id           = (known after apply)
          + throughput            = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + throughput            = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.web_sg will be created
  + resource "aws_security_group" "web_sg" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + asg_arn = [
      + (known after apply),
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.web_sg: Creating...
aws_security_group.web_sg: Creation complete after 8s [id=sg-083d582a5691c56d9]
aws_launch_configuration.my_config: Creating...
aws_launch_configuration.my_config: Creation complete after 2s [id=webserver-launch]
aws_autoscaling_group.first_asg: Creating...
aws_autoscaling_group.first_asg: Still creating... [10s elapsed]
aws_autoscaling_group.first_asg: Still creating... [21s elapsed]
aws_autoscaling_group.first_asg: Still creating... [31s elapsed]
aws_autoscaling_group.first_asg: Still creating... [41s elapsed]
aws_autoscaling_group.first_asg: Creation complete after 45s [id=terraform-20211010125900499300000002]
aws_autoscaling_policy.my_asg_policy: Creating...
aws_autoscaling_policy.my_asg_policy: Creation complete after 2s [id=webservers_autoscale_policy]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

asg_arn = [
  "arn:aws:autoscaling:us-west-2:633602660500:autoScalingGroup:2b023a9d-a66c-464e-9cb0-80d9eef00e33:autoScalingGroupName/terraform-20211010125900499300000002",
]

Result on EC2 AWS

3 Instance EC2

Auto Scaling: Launch configurations

Auto Scaling groups

Conclusion

You have to deploy cluster web servers in the Auto Scaling Group. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Terraform deploy cluster web servers

#Introduction

In this tutorial, How to deploy cluster web servers use Terraform. For example, I will use Terraform deploy cluster web servers.

  • Create EC2 instance
  • Terraform parameter Count: I will create three EC2 instance use Count parameter
  • User user_data and create a script to install Nginx webserver on amazon linux 2.
  • Security group ingress rule to allow access web server from my laptop ?

Structure folder and files of Terraform deploy cluster web servers

Created Cluster-WebServer folder contains files as below:

main.tf
output.tf
provider.tf
securitygroups.tf
variables.tf

Deploy cluster Web Servers with Terraform

Create new file main.tf with the content as below

resource "aws_instance" "devopsroles-lab01" {
 count = 3
 ami = var.ami
 instance_type = var.instance_type
 vpc_security_group_ids = ["${aws_security_group.webserver_security_group.id}"]
 tags = {
	 Name = "DevopsRoles-${count.index}"
 }
 key_name = "terraform-demo"
 user_data = <<EOF
#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
sudo yum update -y
sudo amazon-linux-extras install nginx1 -y
sudo su -c "/bin/echo 'My Site: DevopsRoles.com' >/usr/share/nginx/html/index.html"
instance_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
sudo su -c "echo $instance_ip >>/usr/share/nginx/html/index.html"
sudo systemctl start nginx
sudo systemctl enable  nginx
EOF
}

On AWS, we created key pair terraform-demo as the picture below

Create a new file provider.tf with the content as below

provider "aws" {
        region = var.region
}

New file securitygroups.tf with the content as below

resource "aws_security_group" "webserver_security_group" { 

    ingress {
        from_port = var.server_port
        to_port = var.server_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }

    ingress {
        from_port = var.ssh_port
        to_port = var.ssh_port
        protocol = "tcp"
        cidr_blocks = [ var.my_public_ip ]
    }
egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }    
}

Create a new file output.tf with the content as below

output "public_ip" {
    value = [ "${aws_instance.devopsroles-lab01.*.public_ip}"]
}

Create new file variables.tf with the content as below

variable "region" {
	description = " Define the AWS region "
	default = "us-west-2"
}
variable "server_port" {
	description = "http service listen"
	default = "80"
}

variable "ssh_port" {
	description = "ssh to server"
	default = "22"
}
variable "instance_type" { 
	description = "AWS ec2 instance type"
	default="t2.micro"
}
variable "my_public_ip" {
	description = "My laptop public IP ..." 
        default = "116.110.26.150/32"
}
variable "ami" {
description = "amazon machine image"
default = "ami-0c2d06d50ce30b442"
}

variable "azs" {
default = [ "us-east-2a", "us-east-2b", "us-east-2c"]
}

First, we run below to initialize, download the plugins and validate the terraform syntax…

terraform init
terraform validate

The output terminal is as follows

Applying a template

$ terraform apply

The output terminal is as below

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>set AWS_PROFILE=devopsroles-demo
C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.devopsroles-lab01[0] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-0"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-0"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_instance.devopsroles-lab01[1] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-1"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-1"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_instance.devopsroles-lab01[2] will be created
  + resource "aws_instance" "devopsroles-lab01" {
      + ami                                  = "ami-0c2d06d50ce30b442"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "terraform-demo"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "DevopsRoles-2"
        }
      + tags_all                             = {
          + "Name" = "DevopsRoles-2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "e210837ad2017cf0971bc0ed4af86edab9d8a10d"
      + user_data_base64                     = (known after apply)
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.webserver_security_group will be created
  + resource "aws_security_group" "webserver_security_group" {
      + arn                    = (known after apply)
      + description            = "Managed by Terraform"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
          + {
              + cidr_blocks      = [
                  + "116.110.26.150/32",
                ]
              + description      = ""
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = (known after apply)
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + public_ip = [
      + [
          + (known after apply),
          + (known after apply),
          + (known after apply),
        ],
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.webserver_security_group: Creating...
aws_security_group.webserver_security_group: Creation complete after 8s [id=sg-05fe82255b21a2c8b]
aws_instance.devopsroles-lab01[1]: Creating...
aws_instance.devopsroles-lab01[0]: Creating...
aws_instance.devopsroles-lab01[2]: Creating...
aws_instance.devopsroles-lab01[0]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [10s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [20s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [30s elapsed]
aws_instance.devopsroles-lab01[0]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[1]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[2]: Still creating... [40s elapsed]
aws_instance.devopsroles-lab01[0]: Creation complete after 42s [id=i-0ade24acdfd72944c]
aws_instance.devopsroles-lab01[1]: Creation complete after 42s [id=i-00daeeee26f9dcd20]
aws_instance.devopsroles-lab01[2]: Creation complete after 43s [id=i-0b77263afa926a374]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

public_ip = [
  [
    "54.189.128.5",
    "52.27.217.183",
    "54.201.82.158",
  ],
]

C:\Users\HuuPV\Desktop\Terraform\Cluster_WebServer>

The result, on EC2 AWS

Open Browser, type http://IP_Public_EC2 as below

Webserver 1

Webserver 2

Webserver 3

Conclusion

You have use Terraform deploy cluster web servers. I hope will this your helpful. Thank you for reading the DevopsRoles page!

Devops Tutorial

Exit mobile version