[AWS CDK] 一撃でIPアドレスベースのApache HTTP ServerとApache TomcatのVirtual Hostが動作しているEC2インスタンスを作成してみた

シェルスクリプト最高
2023.08.27

一撃でIPアドレスベースのApache HTTP ServerとApache TomcatのVirtual Hostが動作しているEC2インスタンスを作成したい

こんにちは、のんピ(@non____97)です。

皆さんは一撃でIPアドレスベースのApache HTTP ServerとApache TomcatのVirtual Hostが動作しているEC2インスタンスを作成したいなと思ったことはありますか? 私はちょっとあります。

以前、以下記事でApache HTTP ServerとApache TomcatのVirtual Hostが動作しているEC2インスタンスをAuto ScalingさせてALBで接続できる環境を一撃で用意しました。

ただ、いきなりALBとAuto Scaling上で検証するのも料金が嵩みます。まずは手元で軽く確認をしたいところです。

そこで、Virtual HostのApache HTTP ServerとApache Tomcatが動作しているEC2インスタンスを作成してみたいと思います。また、ただネームベースのVirtual Hostの設定をしても面白くないので、IPベースのVirtual Hostの設定をしてみます。

構成

構成は以下の通りです。

何となく、EC2インスタンスの2つ目のENIに割り当てた2つのIPアドレスそれぞれにVirtual Hostを設定します。

[AWS CDK] 一撃でIPアドレスベースのVirtual HostのApache HTTP ServerとApache Tomcatが動作しているEC2インスタンスを作成してみた検証環境構成図

AWS CDKのコードは以下リポジトリに保存しています。

やっていること

ほとんど前回の記事と同じような処理をしています。

今回はIPベースのVirtual Host用に追加でENIをアタッチしました。追加したENIにはデフォルトのENIと同じセキュリティグループを割り当てるようにします。

./lib/constructs/web-ec2-instance.ts

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as fs from "fs";
import * as path from "path";

export interface WebEc2InstanceProps {
  vpc: cdk.aws_ec2.IVpc;
}

export class WebEc2Instance extends Construct {
  readonly instance: cdk.aws_ec2.Instance;

  constructor(scope: Construct, id: string, props: WebEc2InstanceProps) {
    super(scope, id);

    // Key pair
    const keyName = "test-key-pair";
    const keyPair = new cdk.aws_ec2.CfnKeyPair(this, "KeyPair", {
      keyName,
    });
    keyPair.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY);

    // User data
    const userDataScript = fs.readFileSync(
      path.join(__dirname, "../ec2/user-data.sh"),
      "utf8"
    );
    const userData = cdk.aws_ec2.UserData.forLinux({
      shebang: "#!/bin/bash",
    });
    userData.addCommands(userDataScript);

    // Instance
    this.instance = new cdk.aws_ec2.Instance(this, "Default", {
      machineImage: cdk.aws_ec2.MachineImage.lookup({
        name: "RHEL-9.2.0_HVM-20230726-x86_64-61-Hourly2-GP2",
        owners: ["309956199498"],
      }),
      instanceType: new cdk.aws_ec2.InstanceType("t3.micro"),
      blockDevices: [
        {
          deviceName: "/dev/sda1",
          volume: cdk.aws_ec2.BlockDeviceVolume.ebs(10, {
            volumeType: cdk.aws_ec2.EbsDeviceVolumeType.GP3,
            encrypted: true,
          }),
        },
      ],
      vpc: props.vpc,
      vpcSubnets: props.vpc.selectSubnets({
        subnetGroupName: "Public",
      }),
      keyName,
      ssmSessionPermissions: true,
      userData,
      requireImdsv2: false,
    });

    // ENI
    const eni = new cdk.aws_ec2.CfnNetworkInterface(this, "Eni", {
      subnetId: props.vpc.selectSubnets({
        subnetGroupName: "Public",
        onePerAz: true,
      }).subnetIds[0],
      secondaryPrivateIpAddressCount: 1,
      groupSet: [this.instance.connections.securityGroups[0].securityGroupId],
    });

    new cdk.aws_ec2.CfnNetworkInterfaceAttachment(this, "AttachEni", {
      instanceId: this.instance.instanceId,
      deviceIndex: "1",
      networkInterfaceId: eni.ref,
    });

    // Output
    // Key pair
    new cdk.CfnOutput(this, "GetSecretKeyCommand", {
      value: `aws ssm get-parameter --name /ec2/keypair/${keyPair.getAtt(
        "KeyPairId"
      )} --region ${
        cdk.Stack.of(this).region
      } --with-decryption --query Parameter.Value --output text > ./key-pair/${keyName}.pem`,
    });
  }
}

なお、デフォルトのENIでセカンダリIPアドレスを割り当てたい場合は、以下のようにEscape Hatchesを活用します。

    const cfnInstance = this.instance.node
      .defaultChild as cdk.aws_ec2.CfnInstance;
    cfnInstance.networkInterfaces = [
      {
        deviceIndex: "0",
        subnetId: props.vpc.selectSubnets({
          subnetGroupName: "Public",
          onePerAz: true,
        }).subnetIds[0],
        secondaryPrivateIpAddressCount: 1,
        groupSet: [this.instance.connections.securityGroups[0].securityGroupId],
      },
    ];
    cfnInstance.addPropertyDeletionOverride("SecurityGroupIds");
    cfnInstance.addPropertyDeletionOverride("SubnetId");

EC2インスタンスにアタッチできるENIの数、ENIあたりのIPアドレスの数はインスタンスタイプごとによって異なります。大量のIPアドレスを割り当てる場合は注意しましょう。詳細は以下AWS公式ドキュメントをご覧ください。

追加するENIの作成タイミングはEC2インスタンスと同じではありません。EC2インスタンスが作成されてからENIのアタッチまでラグがあります。このままユーザーデータで追加したENIに割り当てられているIPアドレスを使ってVirtual Hostを設定しようにも、ENIを認識できていないので失敗します。

そのため、追加したENIを認識するまで1秒間隔でチェックしてループする処理を組み込んでいます。

./lib/ec2/user-data.sh

# Wait for eth1 to be found
while true; do
    if nmcli device show eth1 > /dev/null 2>&1; then
        echo "Device 'eth1' found."
        break
    else
        echo "Device 'eth1' not found. waiting 1 second"
        sleep 1
    fi
done

# List IP Address
ip_addrs=($(nmcli device show eth1 \
  | grep IP4.ADDRESS \
  | awk -F "[:/]" '{print $2}' \
  | tr -d ' '))

echo "${ip_addrs[@]}"

追加したENIを認識できたら、そのIPアドレスを変数に代入しています。

こちらの変数を使ってVirtual Hostの設定を行います。Aliasを設定する必要はないですが、気分で付けています。

./lib/ec2/user-data.sh

# Virtual Host
line_num_engine_end=$(($(grep -n '</Engine>' ./tomcat/conf/server.xml | cut -d : -f 1)))
insert_text=$(cat <<EOF

     <Host name="${ip_addrs[0]}" appBase="hoge"
          unpackWARs="true" autoDeploy="false" >
          <Alias>hoge.web.non-97.net</Alias>
          <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/var/log/tomcat"
               prefix="hoge_access_log" suffix=".log" rotatable="false"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
     </Host>

     <Host name="${ip_addrs[1]}" appBase="fuga"
          unpackWARs="true" autoDeploy="false" >
          <Alias>fuga.web.non-97.net</Alias>
          <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/var/log/tomcat"
               prefix="fuga_access_log" suffix=".log" rotatable="false"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
     </Host>
EOF
)
awk -v n=$line_num_engine_end \
  -v s="$insert_text" \
    'NR == n {print s} {print}' ./tomcat/conf/server.xml \
  > tmpfile && mv -f tmpfile ./tomcat/conf/server.xml

httpdでについても同じように設定をします。ユーザーデータ全体は以下の通りです。

./lib/ec2/user-data.sh

#!/bin/bash

# -x to display the command to be executed
set -xe

# Redirect /var/log/user-data.log and /dev/console
exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>&1

# Install Packages
token=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
region_name=$(curl -H "X-aws-ec2-metadata-token: $token" -v http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')

dnf install -y "https://s3.${region_name}.amazonaws.com/amazon-ssm-${region_name}/latest/linux_amd64/amazon-ssm-agent.rpm" \
  java-17-openjdk \
  httpd

# SSM Agent
systemctl enable amazon-ssm-agent
systemctl start amazon-ssm-agent

# Wait for eth1 to be found
while true; do
    if nmcli device show eth1 > /dev/null 2>&1; then
        echo "Device 'eth1' found."
        break
    else
        echo "Device 'eth1' not found. waiting 1 second"
        sleep 1
    fi
done

# List IP Address
ip_addrs=($(nmcli device show eth1 \
  | grep IP4.ADDRESS \
  | awk -F "[:/]" '{print $2}' \
  | tr -d ' '))

echo "${ip_addrs[@]}"

# Tomcat 10
# Install
cd /usr/local/
curl https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.13/bin/apache-tomcat-10.1.13.tar.gz -o apache-tomcat-10.1.13.tar.gz
tar zxvf apache-tomcat-10.1.13.tar.gz
rm -rf apache-tomcat-10.1.13.tar.gz

# symbolic link
ln -s apache-tomcat-10.1.13 tomcat
ls -l | grep tomcat

# Add tomcat user
useradd tomcat -M -s /sbin/nologin
id tomcat

mkdir -p ./tomcat/pid/
mkdir -p /var/log/tomcat/
chown tomcat:tomcat -R ./tomcat/
chown tomcat:tomcat -R /var/log/tomcat/
ls -l | grep tomcat
ls -l ./tomcat/

# setenv.sh
tee ./tomcat/bin/setenv.sh << 'EOF'
export CATALINA_OPTS=" \
  -server \
  -Xms512m \
  -Xmx512m \
  -Xss512k \
  -XX:MetaspaceSize=512m \
  -Djava.security.egd=file:/dev/urandom"
export CATALINA_PID=/usr/local/tomcat/pid/tomcat.pid
export CATALINA_OUT=/var/log/tomcat/catalina.out
EOF

# AJP Connector
line_num_comment_start=$(($(grep -n '<Connector protocol="AJP/1.3"' ./tomcat/conf/server.xml | cut -d : -f 1)-1))
line_num_comment_end=$(tail -n +$(($line_num_comment_start)) ./tomcat/conf/server.xml \
  | grep -n '\-\->' \
  | head -n 1 \
  | cut -d : -f 1
)
line_num_comment_end=$(($line_num_comment_end+$line_num_comment_start-1))
sed -i "${line_num_comment_start}d" ./tomcat/conf/server.xml
sed -i "$((${line_num_comment_end}-1))d" ./tomcat/conf/server.xml
sed -i "$((${line_num_comment_end}-3))a \               secretRequired=\"false\"" ./tomcat/conf/server.xml

# Disable HTTP Connector
line_num_comment_start=$(($(grep -n '<Connector port="8080" protocol="HTTP/1.1"' ./tomcat/conf/server.xml | cut -d : -f 1)-1))
line_num_comment_end=$(tail -n +$(($line_num_comment_start)) ./tomcat/conf/server.xml \
  | grep -n '/>' \
  | head -n 1 \
  | cut -d : -f 1
)
line_num_comment_end=$(($line_num_comment_end+$line_num_comment_start))
sed -i "$((${line_num_comment_start}))a \    <\!\-\-" ./tomcat/conf/server.xml 
sed -i "$((${line_num_comment_end}))a \    \-\->" ./tomcat/conf/server.xml 

# Disable localhost
sed -i '/<Host name="localhost"/,/\/Host>/d' ./tomcat/conf/server.xml 
sed -i 's/defaultHost="localhost"/defaultHost="'${ip_addrs[0]}'"/g' ./tomcat/conf/server.xml

# Virtual Host
line_num_engine_end=$(($(grep -n '</Engine>' ./tomcat/conf/server.xml | cut -d : -f 1)))
insert_text=$(cat <<EOF

     <Host name="${ip_addrs[0]}" appBase="hoge"
          unpackWARs="true" autoDeploy="false" >
          <Alias>hoge.web.non-97.net</Alias>
          <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/var/log/tomcat"
               prefix="hoge_access_log" suffix=".log" rotatable="false"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
     </Host>

     <Host name="${ip_addrs[1]}" appBase="fuga"
          unpackWARs="true" autoDeploy="false" >
          <Alias>fuga.web.non-97.net</Alias>
          <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/var/log/tomcat"
               prefix="fuga_access_log" suffix=".log" rotatable="false"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
     </Host>
EOF
)
awk -v n=$line_num_engine_end \
  -v s="$insert_text" \
    'NR == n {print s} {print}' ./tomcat/conf/server.xml \
  > tmpfile && mv -f tmpfile ./tomcat/conf/server.xml

# logging.properties
# catalina.log
sed -i 's|\${catalina.base}/logs|/var/log/tomcat|g' ./tomcat/conf/logging.properties

# Disable localhost, manager, host-manager
sed -i -E 's/^(2localhost|3manager|4host-manager)/# \1/g' ./tomcat/conf/logging.properties
awk -i inplace '{
  if($0 == "1catalina.org.apache.juli.AsyncFileHandler.maxDays = 90") {
    print "# "$0
    print "1catalina.org.apache.juli.AsyncFileHandler.rotatable = false"
  } else {print $0}
}' ./tomcat/conf/logging.properties
sed -i -E 's/^org.apache.catalina.core.ContainerBase/# &/g' ./tomcat/conf/logging.properties

# Contents
line_num_comment_start=$(($(grep -n 'org.apache.catalina.valves.RemoteAddrValve' ./tomcat/webapps/examples/META-INF/context.xml | cut -d : -f 1)-1))
line_num_comment_end=$(($line_num_comment_start+3))

sed -i "$((${line_num_comment_start}))a <\!\-\-" ./tomcat/webapps/examples/META-INF/context.xml
sed -i "$((${line_num_comment_end}))a \-\->" ./tomcat/webapps/examples/META-INF/context.xml

cp -pr ./tomcat/webapps/ ./tomcat/hoge
cp -pr ./tomcat/webapps/ ./tomcat/fuga

echo "hoge tomcat $(uname -n)" > ./tomcat/hoge/examples/index.html
echo "fuga tomcat $(uname -n)" > ./tomcat/fuga/examples/index.html

rm -rf ./tomcat/webapps/ 

# systemd
tee /etc/systemd/system/tomcat.service << EOF
[Unit]
Description=Apache Tomcat Web Application Container
ConditionPathExists=/usr/local/tomcat
After=syslog.target network.target

[Service]
User=tomcat
Group=tomcat
Type=oneshot
RemainAfterExit=yes

ExecStart=/usr/local/tomcat/bin/startup.sh
ExecStop=/usr/local/tomcat/bin/shutdown.sh

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl list-unit-files --type=service | grep tomcat

systemctl start tomcat
systemctl enable tomcat

# httpd
# Virtual Host
tee /etc/httpd/conf.d/httpd-vhosts.conf << EOF
<VirtualHost ${ip_addrs[0]}:80>
    ServerName hoge.web.non-97.net
    DocumentRoot /var/www/html/hoge

    ProxyPass /tomcat/ ajp://localhost:8009/
    ProxyPassReverse /tomcat/ ajp://localhost:8009/

    <Directory /var/www/html/hoge>
        Options FollowSymLinks
        DirectoryIndex index.html
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/hoge_error_log
    CustomLog /var/log/httpd/hoge_access_log combined
</VirtualHost>

<VirtualHost ${ip_addrs[1]}:80>
    ServerName fuga.web.non-97.net
    DocumentRoot /var/www/html/fuga

    ProxyPass /tomcat/ ajp://localhost:8009/
    ProxyPassReverse /tomcat/ ajp://localhost:8009/

    <Directory /var/www/html/fuga>
        Options FollowSymLinks
        DirectoryIndex index.html
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/fuga_error_log
    CustomLog /var/log/httpd/fuga_access_log combined
</VirtualHost>
EOF

# Disable Welcome page
cat /dev/null > /etc/httpd/conf.d/welcome.conf

# Disable Auto Index
sudo mv /etc/httpd/conf.d/autoindex.conf /etc/httpd/conf.d/autoindex.conf.org
sed -i 's/Options Indexes FollowSymLinks/Options FollowSymLinks/g' /etc/httpd/conf/httpd.conf

# Disable UserDir
mv /etc/httpd/conf.d/userdir.conf /etc/httpd/conf.d/userdir.conf.org

tee /etc/httpd/conf.d/security.conf << EOF
# Hide Apache Version
ServerTokens Prod 

# Hide Header X-Powered-By
Header unset "X-Powered-By"

# Hide bunner in Error Page
ServerSignature off

# Deny open outer web resources for protection of Click Jacking attack
Header append X-Frame-Options SAMEORIGIN

# Protection for MIME Sniffing attack
Header set X-Content-Type-Options nosniff 
Header set X-XSS-Protection "1; mode=block"

# Deny HTTP TRACE Method access for protection of Cross-Site Tracing attack
TraceEnable Off
EOF

# Check syntax
httpd -t

# Contents
mkdir -p /var/www/html/hoge
mkdir -p /var/www/html/fuga

echo "hoge $(uname -n)" > /var/www/html/hoge/index.html
echo "fuga $(uname -n)" > /var/www/html/fuga/index.html

systemctl start httpd
systemctl enable httpd

# SELinux
setsebool -P httpd_can_network_connect=true
getsebool -a

動作確認

動作確認をしてみます。

デプロイ後、WebサーバーのEC2インスタンス自身からIPアドレスを指定してアクセスしてみます。

$ curl 10.10.10.12
fuga ip-10-10-10-22.ec2.internal

$ curl 10.10.10.10
hoge ip-10-10-10-22.ec2.internal


$ curl 10.10.10.12/tomcat/examples/
fuga tomcat ip-10-10-10-22.ec2.internal

$ curl 10.10.10.10/tomcat/examples/
hoge tomcat ip-10-10-10-22.ec2.internal

httpd、Tomcatどちらのコンテンツも表示できましたね。

別のEC2インスタンスからもアクセスしてみます。

$ curl 10.10.10.12
fuga ip-10-10-10-22.ec2.internal

$ curl 10.10.10.10
hoge ip-10-10-10-22.ec2.internal

$ curl 10.10.10.12/tomcat/examples/
fuga tomcat ip-10-10-10-22.ec2.internal

$ curl 10.10.10.10/tomcat/examples/
hoge tomcat ip-10-10-10-22.ec2.internal

こちらもアクセスできました。

アクセスログも確認しておきましょう。

$ sudo cat /var/log/httpd/hoge_access_log
10.10.10.12 - - [27/Aug/2023:02:14:28 +0000] "GET / HTTP/1.1" 200 33 "-" "curl/7.76.1"
10.10.10.12 - - [27/Aug/2023:02:15:24 +0000] "GET /tomcat/examples/ HTTP/1.1" 200 40 "-" "curl/7.76.1"
10.10.10.30 - - [27/Aug/2023:02:26:57 +0000] "GET / HTTP/1.1" 200 33 "-" "curl/8.0.1"
10.10.10.30 - - [27/Aug/2023:02:27:08 +0000] "GET /tomcat/examples/ HTTP/1.1" 200 40 "-" "curl/8.0.1"

$ sudo cat /var/log/httpd/fuga_access_log
10.10.10.12 - - [27/Aug/2023:02:14:18 +0000] "GET / HTTP/1.1" 200 33 "-" "curl/7.76.1"
10.10.10.12 - - [27/Aug/2023:02:15:18 +0000] "GET /tomcat/examples/ HTTP/1.1" 200 40 "-" "curl/7.76.1"
10.10.10.30 - - [27/Aug/2023:02:26:39 +0000] "GET / HTTP/1.1" 200 33 "-" "curl/8.0.1"

$ sudo cat /var/log/tomcat/hoge_access_log.log
10.10.10.12 - - [27/Aug/2023:02:15:24 +0000] "GET /examples/ HTTP/1.1" 200 40
10.10.10.30 - - [27/Aug/2023:02:27:08 +0000] "GET /examples/ HTTP/1.1" 200 40

$ sudo cat /var/log/tomcat/fuga_access_log.log
10.10.10.12 - - [27/Aug/2023:02:15:18 +0000] "GET /examples/ HTTP/1.1" 200 40
10.10.10.30 - - [27/Aug/2023:02:27:03 +0000] "GET /examples/ HTTP/1.1" 200 40

httpd、Tomcatどちらのアクセスログにも記録されていますね。

catalina.logも確認しておきます。

$ sudo cat /var/log/tomcat/catalina.log
27-Aug-2023 02:05:44.248 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/10.1.13
27-Aug-2023 02:05:44.280 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Aug 23 2023 21:34:59 UTC
27-Aug-2023 02:05:44.283 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.13.0
27-Aug-2023 02:05:44.283 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
27-Aug-2023 02:05:44.285 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            5.14.0-284.18.1.el9_2.x86_64
27-Aug-2023 02:05:44.286 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
27-Aug-2023 02:05:44.286 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/lib/jvm/java-17-openjdk-17.0.8.0.7-2.el9.x86_64
27-Aug-2023 02:05:44.287 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           17.0.8+7-LTS
27-Aug-2023 02:05:44.288 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Red Hat, Inc.
27-Aug-2023 02:05:44.288 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/apache-tomcat-10.1.13
27-Aug-2023 02:05:44.291 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/apache-tomcat-10.1.13
27-Aug-2023 02:05:44.351 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
27-Aug-2023 02:05:44.351 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
27-Aug-2023 02:05:44.353 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
27-Aug-2023 02:05:44.354 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
27-Aug-2023 02:05:44.354 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
27-Aug-2023 02:05:44.356 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
27-Aug-2023 02:05:44.356 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
27-Aug-2023 02:05:44.359 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
27-Aug-2023 02:05:44.359 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
27-Aug-2023 02:05:44.359 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
27-Aug-2023 02:05:44.360 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xms512m
27-Aug-2023 02:05:44.360 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx512m
27-Aug-2023 02:05:44.363 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xss512k
27-Aug-2023 02:05:44.367 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -XX:MetaspaceSize=512m
27-Aug-2023 02:05:44.367 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.security.egd=file:/dev/urandom
27-Aug-2023 02:05:44.368 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
27-Aug-2023 02:05:44.368 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
27-Aug-2023 02:05:44.368 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
27-Aug-2023 02:05:44.375 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]
27-Aug-2023 02:05:46.992 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-0:0:0:0:0:0:0:1-8009"]
27-Aug-2023 02:05:47.191 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [4926] milliseconds
27-Aug-2023 02:05:47.509 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
27-Aug-2023 02:05:47.509 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.13]
27-Aug-2023 02:05:47.585 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/fuga/ROOT]
27-Aug-2023 02:05:50.753 WARNING [main] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [669] milliseconds.
27-Aug-2023 02:05:51.267 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/fuga/ROOT] has finished in[3,681] ms
27-Aug-2023 02:05:51.267 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/fuga/examples]
27-Aug-2023 02:05:52.400 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
27-Aug-2023 02:05:52.402 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextInitialized()
27-Aug-2023 02:05:52.405 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: attributeAdded('StockTicker', 'async.Stockticker@64df9a61')
27-Aug-2023 02:05:52.435 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/fuga/examples] has finished in [1,168] ms
27-Aug-2023 02:05:52.436 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/fuga/host-manager]
27-Aug-2023 02:05:52.533 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/fuga/host-manager] has finished in [96] ms
27-Aug-2023 02:05:52.534 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/fuga/manager]
27-Aug-2023 02:05:52.637 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/fuga/manager] has finishedin [103] ms
27-Aug-2023 02:05:52.638 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/fuga/docs]
27-Aug-2023 02:05:52.701 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/fuga/docs] has finished in[61] ms
27-Aug-2023 02:05:52.710 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/hoge/ROOT]
27-Aug-2023 02:05:52.840 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/hoge/ROOT] has finished in[129] ms
27-Aug-2023 02:05:52.841 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/hoge/examples]
27-Aug-2023 02:05:53.313 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextInitialized()
27-Aug-2023 02:05:53.313 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextInitialized()
27-Aug-2023 02:05:53.316 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: attributeAdded('StockTicker', 'async.Stockticker@512d92b')
27-Aug-2023 02:05:53.327 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/hoge/examples] has finished in [486] ms
27-Aug-2023 02:05:53.333 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/hoge/host-manager]
27-Aug-2023 02:05:53.412 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/hoge/host-manager] has finished in [79] ms
27-Aug-2023 02:05:53.412 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/hoge/manager]
27-Aug-2023 02:05:53.485 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/hoge/manager] has finishedin [72] ms
27-Aug-2023 02:05:53.486 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/apache-tomcat-10.1.13/hoge/docs]
27-Aug-2023 02:05:53.535 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/apache-tomcat-10.1.13/hoge/docs] has finished in[48] ms
27-Aug-2023 02:05:53.559 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-0:0:0:0:0:0:0:1-8009"]
27-Aug-2023 02:05:53.630 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [6438] milliseconds
27-Aug-2023 02:28:45.385 INFO [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
27-Aug-2023 02:28:45.387 INFO [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-0:0:0:0:0:0:0:1-8009"]
27-Aug-2023 02:28:45.389 INFO [main] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
27-Aug-2023 02:28:45.423 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextDestroyed()
27-Aug-2023 02:28:45.424 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextDestroyed()
27-Aug-2023 02:28:45.455 INFO [main] org.apache.catalina.core.ApplicationContext.log SessionListener: contextDestroyed()
27-Aug-2023 02:28:45.455 INFO [main] org.apache.catalina.core.ApplicationContext.log ContextListener: contextDestroyed()

特にエラーは出力されずに起動できていますね。

シェルスクリプト最高

一撃でIPアドレスベースのVirtual HostのApache HTTP ServerとApache Tomcatが動作しているEC2インスタンスを作成してみました。

シェルスクリプト最高ですね。何でもできそうな気がします。

ただし、ユーザーデータは16KBという制限があります。

ユーザーデータは raw 形式の 16 KB に制限されます (以前は base64 エンコード)。base64 エンコード後の 文字列の長さサイズ n は、ceil(n/3)*4 です。

インスタンスユーザーデータの使用 - Amazon Elastic Compute Cloud

そのため、あまりにもユーザーデータが巨大なのであれば、実行したいスクリプトのファイルをS3バケットにアップロードして、ユーザーデータでS3バケットからスクリプトファイルをダウンロードして実行するような処理を組み込んであげると良いかと思います。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!