通过Userdata在创建EC2时候修改Hostname主机名

一、背景

Userdata脚本可以在创建EC2时候执行初始化配置。通过AWS Console网页控制台创建EC2时候,可以直接填写在页面上。如果是通过API创建EC2,使用封装的SDK调用,那么应该如何传递参数呢?请看本文例子。

执行如下代码可以设置静态主机名。以下代码对CentOS 7.4以及更高版本有效。

hostnamectl set-hostname --static myapitest5

修改完毕后重启EC2使得Hostname生效。再次登录后检查hostname,可以看到已经设置为固定名称了,且不会因为EC2重启失效。

注:在CentOS 7.4之前系统,还需要修改/etc/cloud/cloud.cfg里的配置preserve_hostname: false,需要设置为true才可以。从CentOS 7.4开始,不需要再修改这个文件了。使用与CentOS 7.x兼容的Amazon Linux 2系统也不需要修改这个设置了。

为了实现通过API开机,现在将这个命令拼装到通过SDK创建EC2的调用过程中即可。本文以AWSCLI和Python为例,其他语言实现方式同理。

二、使用AWSCLI创建EC2并传入Userdata

1、配置AWSCLI

请参考相关文档。

2、构建Userdata脚本

编辑my_script.txt文件,其中定义的主机名为myapitest6。文件内容如下:

#! /bin/bash
yum update -y
yum install httpd -y
echo 'userdata script' > /test.txt
hostnamectl set-hostname --static myapitest6

3、发起创建

aws ec2 --region ap-northeast-1 \
    run-instances \
    --image-id ami-0310b105770df9334 \
    --instance-type t3.small \
    --count 1 \
    --subnet-id subnet-00ebbd9c59ee825da \
    --key-name lxy-tokyo \
    --security-group-ids sg-0d3c44b2989f52ea4 \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=myapitest001}]' \
    --user-data file://my_script.txt

创建后即可看到Hostname已经配置成功。

三、使用Python Boto3 SDK创建EC2并传入Userdata

1、环境准备

首先安装Python语言的SDK即Boto3环境:

pip3 install boto3

此外,本机也配置好AWSCLI,因为Python boto3默认会调用和AWSCLI相同的config和credential配置文件做身份验证。

2、示例代码

运行如下代码,请调整参数为对应的本Region的实际信息。

import boto3

DEVICE_NAME = '/dev/xvda'
DISK_SIZE_GB = 10
AMI_IMAGE_ID = 'ami-0310b105770df9334'
INSTANCE_TYPE = 't3.small'
KEY_NAME = 'lxy-tokyo'
SECURITY_GROUPS_IDS = ['sg-0d3c44b2989f52ea4']
SUBNET_ID = 'subnet-00ebbd9c59ee825da'
# Hostname和tag这里设置为一样的,方便从AWS Console上浏览和查找
TAG_NAME = 'Name'
TAG_VALUE = 'myapitest6'
HOST_NAME = TAG_VALUE
USERDATA_SCRIPT = """#! /bin/bash
yum update -y
yum install httpd -y
echo 'userdata script' > /test.txt
hostnamectl set-hostname --static """ + HOST_NAME

client = boto3.client('ec2')

response = client.run_instances(
    BlockDeviceMappings=[
        {
            'DeviceName': DEVICE_NAME,
            'Ebs': {
                'VolumeSize': DISK_SIZE_GB,
                'VolumeType': 'gp3',
                'Encrypted': True
            }
        }
    ],
    ImageId = AMI_IMAGE_ID,
    InstanceType = INSTANCE_TYPE,
    KeyName = KEY_NAME,
    MaxCount = 1,
    MinCount = 1,
    Monitoring = {
        'Enabled': True
    },
    SecurityGroupIds = SECURITY_GROUPS_IDS, 
    SubnetId = SUBNET_ID,
    UserData = USERDATA_SCRIPT,
    EbsOptimized = True,
    TagSpecifications = [
        {
            'ResourceType': 'instance',
            'Tags': [
                {
                    'Key': TAG_NAME,
                    'Value': TAG_VALUE
                }
            ]
        }
    ]
)

print(response)

注意以上代码中,Userdata的开头必须是#!/ bin/bash,然后必须接一个换行符。以上代码片段已经包含换行,请不要删除这个换行。如果实际提交给API的Userdata在#!/ bin/bash之后不包含包含\n换行符的话,Userdata将不生效。

程序运行后返回结果如下:

{'Groups': [], 'Instances': [{'AmiLaunchIndex': 0, 'ImageId': 'ami-0310b105770df9334', 'InstanceId': 'i-02e3ba34cdfce6d97', 'InstanceType': 't3.small', 'KeyName': 'lxy-tokyo', 'LaunchTime': datetime.datetime(2023, 9, 1, 3, 59, 36, tzinfo=tzlocal()), 'Monitoring': {'State': 'pending'}, 'Placement': {'AvailabilityZone': 'ap-northeast-1c', 'GroupName': '', 'Tenancy': 'default'}, 'PrivateDnsName': 'ip-172-16-0-17.ap-northeast-1.compute.internal', 'PrivateIpAddress': '172.16.0.17', 'ProductCodes': [], 'PublicDnsName': '', 'State': {'Code': 0, 'Name': 'pending'}, 'StateTransitionReason': '', 'SubnetId': 'subnet-00ebbd9c59ee825da', 'VpcId': 'vpc-0f35fc724267a5b26', 'Architecture': 'x86_64', 'BlockDeviceMappings': [], 'ClientToken': '9bebef5f-0f39-4ebf-a94b-68aff234bc60', 'EbsOptimized': True, 'EnaSupport': True, 'Hypervisor': 'xen', 'NetworkInterfaces': [{'Attachment': {'AttachTime': datetime.datetime(2023, 9, 1, 3, 59, 36, tzinfo=tzlocal()), 'AttachmentId': 'eni-attach-04393e6918cc77765', 'DeleteOnTermination': True, 'DeviceIndex': 0, 'Status': 'attaching', 'NetworkCardIndex': 0}, 'Description': '', 'Groups': [{'GroupName': 'allow-ssh', 'GroupId': 'sg-0d3c44b2989f52ea4'}], 'Ipv6Addresses': [], 'MacAddress': '0a:40:e9:82:cf:cb', 'NetworkInterfaceId': 'eni-0cd282c96ce39002b', 'OwnerId': '133129065110', 'PrivateIpAddress': '172.16.0.17', 'PrivateIpAddresses': [{'Primary': True, 'PrivateIpAddress': '172.16.0.17'}], 'SourceDestCheck': True, 'Status': 'in-use', 'SubnetId': 'subnet-00ebbd9c59ee825da', 'VpcId': 'vpc-0f35fc724267a5b26', 'InterfaceType': 'interface'}], 'RootDeviceName': '/dev/xvda', 'RootDeviceType': 'ebs', 'SecurityGroups': [{'GroupName': 'allow-ssh', 'GroupId': 'sg-0d3c44b2989f52ea4'}], 'SourceDestCheck': True, 'StateReason': {'Code': 'pending', 'Message': 'pending'}, 'Tags': [{'Key': 'Name', 'Value': 'myapitest4'}], 'VirtualizationType': 'hvm', 'CpuOptions': {'CoreCount': 1, 'ThreadsPerCore': 2}, 'CapacityReservationSpecification': {'CapacityReservationPreference': 'open'}, 'MetadataOptions': {'State': 'pending', 'HttpTokens': 'required', 'HttpPutResponseHopLimit': 2, 'HttpEndpoint': 'enabled', 'HttpProtocolIpv6': 'disabled', 'InstanceMetadataTags': 'disabled'}, 'EnclaveOptions': {'Enabled': False}, 'BootMode': 'uefi-preferred', 'PrivateDnsNameOptions': {'HostnameType': 'ip-name', 'EnableResourceNameDnsARecord': True, 'EnableResourceNameDnsAAAARecord': False}, 'MaintenanceOptions': {'AutoRecovery': 'default'}, 'CurrentInstanceBootMode': 'uefi'}], 'OwnerId': '133129065110', 'ReservationId': 'r-0c67a5b46eefdb33f', 'ResponseMetadata': {'RequestId': '9ede87e8-f7c6-400f-aa1f-d7bc72f703d5', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '9ede87e8-f7c6-400f-aa1f-d7bc72f703d5', 'cache-control': 'no-cache, no-store', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'vary': 'accept-encoding', 'content-type': 'text/xml;charset=UTF-8', 'content-length': '5641', 'date': 'Fri, 01 Sep 2023 03:59:35 GMT', 'server': 'AmazonEC2'}, 'RetryAttempts': 0}}

3、登录到EC2内检查结果

登录后可看到Hostname修改成功,用于测试的/test.txt也被正常创建好。

四、参考文档

如何为运行 RHEL 7 或 CentOS 7 的 Amazon EC2 实例分配静态主机名:

https://repost.aws/zh-Hans/knowledge-center/linux-static-hostname-rhel7-centos7

更改 Amazon Linux 实例的主机名:

https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/set-hostname.html

EC2 Java V2 SDK的Userdata配置说明:

https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/model/UserData.html