How to run scritps after create ec2 using terraform during apply?

Viewed 5931

In terraform there is an example to create EC2 machine in aws.

# Create a new instance of the latest Ubuntu 20.04 on an
# t3.micro node with an AWS Tag naming it "HelloWorld"
provider "aws" {
  region = "us-west-2"
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  tags = {
    Name = "HelloWorld"
  }
}

But can I also run some scripts inside? like install jenkins? install docker, or just run command: sudo yum update -y during terraform apply operation?

If so, I would much appropriate an example of something like that or guide resource.

3 Answers

Yes, you can. In AWS, you use UserData for that which:

can be used to perform common automated configuration tasks and even run scripts after the instance starts.

In terraform, the corresponding attribute is user_data.

To use it to install Jenkins you can try the following:

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  user_data = <<-EOL
  #!/bin/bash -xe

  apt update
  apt install openjdk-8-jdk --yes
  wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
  echo "deb https://pkg.jenkins.io/debian binary/" >> /etc/apt/sources.list
  apt update
  apt install -y jenkins
  systemctl status jenkins
  find /usr/lib/jvm/java-1.8* | head -n 3  
  EOL

  tags = {
    Name = "HelloWorld"
  }
}

Please note, that the above code is example and I can't guarantee it will work on Ubuntu 20.04. But it works on 18.04. Also Jenksis works on port 8080, so your security groups would need to allow it, if you want to access jenkins directly, without ssh tunnel for instance.

There is also the Option of Provisioners but Terraform has a Note on it

/// From TF Documentation /// Note: Provisioners should only be used as a last resort. For most common situations there are better alternatives. For more information, see the main Provisioners page. ///

Please see these link before you decide to you it: https://www.terraform.io/docs/provisioners/index.html https://www.terraform.io/docs/provisioners/remote-exec.html

I am posting a simple example anyway.

resource "aws_instance" "WebServer"  {
  ami           = "ami-SomeValid_AMI_ID"
  instance_type = "t2.micro"
  key_name = "SomeValid_keypair"
   
    provisioner "remote-exec" {
    
    inline = [
    "sudo amazon-linux-extras install -y nginx1.12",
    "sudo systemctl start nginx"
    ]
    
    connection {
    type = "ssh"
    user = "ec2-user"
    private_key = file("F:\\PathToMyKeysFolder\\SomeValid_keypair.pem")
    host = self.public_ip
    
    }
    
    }

Note:

AWS allows us to update "User Data" directly in the console in an Existing Instance provided it is in stopped state. One would expect Terraform also to behave the same way, where you would update your "user_data" section in Terraform script and during the next apply it gets updated in AWS, if the server was in stopped state. But NO.

If you are updating the user_data in an existing EC2 instance via terraform, the instance will get recreated --> Destroy and Add. "Terraform Plan" will show this anyway (I am not sure whats the logic behind it yet, but that's how it seems to be as of today, so be careful about it).

    # aws_instance.my-instance **must be replaced**\
.....
.....
    Plan: **1 to add**, 0 to change, **1 to destroy**.

And same issue if you do changes manually in AWS console - terraform will pick up the change and tell that it has to recreate the server.

Related