In this lab exercise, we will create an EC2 Virtual Machine Instance as an external test client. EC2 Virtual Machine is a suitable alternative where you may not want to test your local machine due to security, latency, or other reasons. Creating a dedicated Virtual Machine Instance in the same VPC allows us to easily size our test client adequately for performance benchmarking
To access our client externally need to have an appropriate security groupset and a key-pair to connect over SSH: you can make a security group in the AWS management console website or follow the instructions to set up a security group, key-pair, and EC2 instance using the AWS CLI
- Create a Security Group to open only the SSH port in inbound and opens
all ports in outbound. You can make a security group on the AWS website or
create a security group, for instance, for remote SSH
port 22
Access:
MY_SECURITY_GROUP=security-group-uswest2-armand
aws ec2 create-security-group --group-name $MY_SECURITY_GROUP --description "security group with open port 22"
aws ec2 authorize-security-group-ingress --group-name $MY_SECURITY_GROUP \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0
aws ec2 describe-security-groups --group-names $MY_SECURITY_GROUP
To get the security group ID for later steps, you can use the following query filter
MY_SECURITY_GROUP=security-group-uswest2-armand
MY_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --group-names $MY_SECURITY_GROUP --query 'SecurityGroups[*].[GroupId]' --output text)
echo $MY_SECURITY_GROUP_ID
- Create a key-pair for Public Key authentication for SSH. You can use your key pair. However, the public key should be in AWS, and the private key should be kept on your computer.
Important: Because AWS doesn't keep a copy of your private key, there is no way to recover a private key if you lose it. However, there can still be a way to connect to instances that use a lost key pair
Create a key-pair
MY_KEY_PAIR=keypair-armand
aws ec2 create-key-pair --key-name $MY_KEY_PAIR --output text > $MY_KEY_PAIR.pem
Some extra steps
# Describe your key-pair at any time
MY_KEY_PAIR=keypair-armand
aws ec2 describe-key-pairs --key-name $MY_KEY_PAIR
# IF you need to delete your key pair
MY_KEY_PAIR=keypair-armand
aws ec2 delete-key-pair --key-name $MY_KEY_PAIR
-
Clean up Private key for ssh use using a text editor (e.g.,
vi
) and make sure the file starts and ends with the standard,-----BEGIN RSA PRIVATE KEY-----
at the beginning of the file and-----END RSA PRIVATE KEY-----
at the end of the file-----BEGIN RSA PRIVATE KEY----- [your private key here] -----END RSA PRIVATE KEY-----
For example, the raw private key generated by AWS needs can be cleaned up like so
- Set secure permission on the file:
MY_KEY_PAIR=keypair-armand
chmod 400 $MY_KEY_PAIR.pem
- Launch a
t2.micro
instance in the specified subnet of a VPC. Replace the[my_image_id]
parameter values with your own. To find theimage-id
you need, check out Finding a Linux AMI or other resources such as Ubuntu Cloud Image Finder. Note that AMI IDs are unique to each AWS Region, therefore ensuring you have found an AMI available in your VPC region.
--image-id
: Find an image in your region using Ubuntu Cloud Image Finder, e.g.,ami-082e4f383a98efbe9
: Ubuntu 20.04 LTS (HVM), SSD Volume Type, in us-west-2--count
:1
--key-name
: reference your key-pair, e.g.,$MY_KEY_PAIR
, the key pair that we made above--security-group-ids
: Security group ID
MY_KEY_PAIR=keypair-armand
MY_NAME=armand
MY_SECURITY_GROUP=security-group-uswest2-armand
MY_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --group-names $MY_SECURITY_GROUP --query 'SecurityGroups[*].[GroupId]' --output text)
MY_EC2_NAME=ec2-uswest2-armand
MY_IMAGE_ID=ami-082e4f383a98efbe9
aws ec2 run-instances \
--image-id $MY_IMAGE_ID \
--count 1 \
--instance-type t2.micro \
--key-name $MY_KEY_PAIR \
--security-group-ids $MY_SECURITY_GROUP_ID \
--tag-specifications "ResourceType=instance,Tags=[{Key=user,Value=$MY_NAME},{Key=Name,Value=$MY_EC2_NAME}]"
- Check the status of the EC2 instance. When the instance is ready, the output
should have "
running
"
# Get instance state details [InstanceId, ImageId, State.Code, State.Name]
MY_EC2_NAME=ec2-apsoutheast2-armand
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=$MY_EC2_NAME" \
--query "Reservations[*].Instances[*].[InstanceId, ImageId, State.code, State.Name]" --o text \
--output text
- Retrieve the EC2 instance Public IP Address. This information will be useful later
MY_EC2_NAME=ec2-uswest2-armand
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=$MY_EC2_NAME" \
--query "Reservations[*].Instances[*].PublicIpAddress" \
--output=text
- Check out General prerequisites for connecting to your instance, to find out the default username for the AMI you used to launch your Virtual Machine instance. Generally, it is:
* For Amazon Linux 2 or the Amazon Linux AMI, the user name is ec2-user.
* For a CentOS AMI, the user name is centos.
* For a Debian AMI, the user name is admin.
* For a Fedora AMI, the user name is ec2-user or fedora.
* For a RHEL AMI, the user name is ec2-user or root.
* For a SUSE AMI, the user name is ec2-user or root.
* For an Ubuntu AMI, the user name is ubuntu.
* Otherwise, if ec2-user and root don't work, check with the AMI provider..
- Set key file permission and Access to the Virtual Machine instance using ssh
MY_KEY_PAIR=keypair-armand
MY_EC2_NAME=ec2-uswest2-armand
MY_EC2_PUBLIC_IP=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=$MY_EC2_NAME" \
--query "Reservations[*].Instances[*].PublicIpAddress" \
--output=text)
MY_USERNAME=ubuntu #e.g. Ubuntu AMI
ssh -i $MY_KEY_PAIR.pem $MY_USERNAME@$MY_EC2_PUBLIC_IP
Troubleshooting: If you are getting a Invalid Format
error, make sure your
private key started with -----BEGIN RSA PRIVATE KEY-----
and ends with
-----END RSA PRIVATE KEY-----
. See Clean up Private key for
ssh
We can deploy a utility docker container,
network-tools
, to run
various HTTP tools to make requests to Externally accessible applications in our
Kubernetes cluster. See the
readme
for the complete
list of tools
For example We can run the following tools from the client machine using a alias to the docker container
# HTTPIE - https://httpie.io/ - HTTP client for the API era
alias http='docker run --rm -it armsultan/network-tools http'
# WRK - https://github.com/wg/wr) - modern HTTP benchmarking tool
# capable of generating significant load when run on a single multi-core CPU
alias wrk='docker run --rm -it armsultan/network-tools wrk'
# WRK2 - https://github.com/giltene/wrk2 - wrk2 is wrk modifed to produce
# a constant throughput load, and accurate latency
alias wrk2='docker run --rm -it armsultan/network-tools wrk2'
# VEGETA - https://github.com/tsenart/vegeta - Versatile HTTP load testing
# tool built out of a need to drill HTTP services with a constant request rate
alias vegeta='docker run --rm -it armsultan/network-tools vegeta'
# FORTIO - https://github.com/fortio/fortio - started as, and is, Istio's
# load testing tool and now graduated to be its own project
alias fortio='docker run --rm -it armsultan/network-tools fortio'
# testssl.sh - https://testssl.sh/ - tool which checks a server's service
# on any port for the support of TLS/SSL ciphers, protocols as well as recent
# cryptographic flaws and more.
alias testssl.sh='docker run --rm -ti armsultan/network-tools testssl.sh'
Alternatively, you can run any command in the container using the docker run
command. For example:
# docker run --rm -i armsultan/network-tools sh -c [command here]
# e.g.
docker run --rm -i armsultan/network-tools sh -c \
"echo 'GET https://www.example.com' | vegeta attack -rate=10 -duration=30s -insecure | tee results.bin | vegeta report"
- Install Docker on your Client machine (i.e., your EC2 Virtual Machine instance, where you will l running your HTTP test). Follow the correct instructions to install on your OS
Note: To run docker as non-root, According to the official Docker docs, You need to do the following:
# To create the docker group and add your user:
# Create the docker group.
sudo groupadd docker
# Add your user to the docker group.
sudo usermod -aG docker ${USER}
# Now LOG OUT and log back in so that your group membership is
# re-evaluated or type the following command:
su -s ${USER}
- Pull the docker image so that it is readily available
docker pull armsultan/network-tools
-
From your AWS CLI Client: Get the External IP address of your ingress so that we can run a
vegeta
load test against your ingress controller and applications from your HTTP Client Machine (EC2) in the next stepJust like in the Lab excerise: Expose a sample application with ingress, we want to get the external IP address. This time we will use
vegeta
to make high volume requests for load testing
From your AWS CLI Client: For example, if we have exposed Ingress with a
loadBalancer
, grab the external IP address of that Load Balancer and copy it
to be used for out load testing tool on our EC2 HTTP client Machine
# Get External loadBalancer address
LB_FQDN=$(kubectl get services/nginx-ingress -n nginx-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')
# Get loadBalancer IP address
dig +short $LB_FQDN A | awk 'NR==1'
- From your HTTP Client Machine (EC2): Run a few test
curl
requests with the External IP Address ($EXT_IP) into the and if successful, run avegeta
load test
Run some curl
commands
EXT_IP=13.236.129.173
# Get coffee
curl https://cafe.example.com/coffee --insecure \
--resolve cafe.example.com:80:$EXT_IP \
--resolve cafe.example.com:443:$EXT_IP
# Get tea:
curl https://cafe.example.com/tea --insecure \
--resolve cafe.example.com:80:$EXT_IP \
--resolve cafe.example.com:443:$EXT_IP
Now run a vegeta
load test
EXT_IP=13.236.129.173
docker run --rm -i armsultan/network-tools sh -c \
"echo 'GET https://$EXT_IP/coffee' | vegeta attack -rate=10 -duration=30s -header 'Host: cafe.example.com' -insecure | tee results.bin | vegeta report"
Here is an example result. All successful HTTP 200
with no errors:
Requests [total, rate, throughput] 300, 10.03, 10.03
Duration [total, attack, wait] 29.905s, 29.9s, 5.135ms
Latencies [min, mean, 50, 90, 95, 99, max] 2.578ms, 4.568ms, 4.82ms, 5.367ms, 5.551ms, 8.29ms, 18.658ms
Bytes In [total, mean] 15343345, 51144.48
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:300
Error Set:
- Delete EC2 instance
MY_EC2_NAME=ec2-uswest2-armand
MY_EC2_INSTANCE_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=$MY_EC2_NAME" \
--query 'Reservations[].Instances[].InstanceId' \
--output text)
aws ec2 terminate-instances --instance-ids $MY_EC2_INSTANCE_ID
- Delete security group
MY_SECURITY_GROUP=security-group-uswest2-armand
aws ec2 create-security-group --group-name $MY_SECURITY_GROUP
- Delete your key pair
MY_KEY_PAIR=keypair-armand
aws ec2 delete-key-pair --key-name $MY_KEY_PAIR