Lecture 17 - Cloud Computing II
us-east-1 outageCartoon by Forrest Brazeal
requestsdata/raw/. The report reads only that snapshotThe starter repository: https://github.com/danilofreire/datasci350-project-starter
| Component | Weight |
|---|---|
| Reproducibility | 30% |
| Analysis quality | 30% |
| Communication | 20% |
| Code quality | 10% |
| Git workflow | 10% |
If docker run on my machine does not reproduce your report, your project does not exist 😅
chmod worksapt and copy files with scpaws command linet3.microSource: DataCamp
ls, cd, pwd, and so onsudo runs a command as root, the superuserapt (Advanced Package Tool) installs software
apt update refreshes the package listapt install installs a packagesudo apt install python3 installs Pythonsudo apt install python3-pip installs pipDownloads, which WSL sees as /mnt/c/Users/<your-windows-name>/Downloads/C: ignore chmod and always look open to everyoneWARNING: UNPROTECTED PRIVATE KEY FILE!chmod it therels /mnt/c/Users/Linux in the left panelUbuntu in the Start menu/home/<your-linux-name>, or ~C: drive: /mnt/c/# 1. Copy the key from Downloads to your Linux home
cp /mnt/c/Users/<your-windows-name>/Downloads/datasci350.pem ~/
# 2. Make it readable only by you
chmod 400 ~/datasci350.pem
# 3. Check: the line should start with -r--------
ls -l ~/datasci350.pem
# 4. Connect as usual
ssh -i ~/datasci350.pem ubuntu@<your-public-dns>Still stuck? If SSH refuses your key after these steps, connect from CloudShell instead. It runs Linux in your browser, so chmod works. Steps in the appendix
The EC2 Dashboard
Name and tags, such as datasci350Application and OS Images, choose UbuntuUbuntu Server 26.04 LTS, marked Free tier eligible64-bit (x86) as the architectureSummary panel on the right lists every choice before you launchThe launch wizard. Click the image to read the Summary panel
t3.micro, labelled Free tier eligiblet3.micro, t3.small, t4g.micro, t4g.small, c7i-flex.large and m7i-flex.larget3.micro has 2 vCPUs and 1 GiB of memory, and costs 0.0104 USD an hour on LinuxIgnore the blue Free tier note in Summary. It describes the old t2.micro offer (750 hours a month for a year), closed to new accounts on 15 July 2025. Your account runs on credits instead
Create a new key pair and name it, e.g. datasci350ED25519 and the .pem file formatCreate key pair and save the file somewhere safeNetwork settings, tick Allow HTTPS traffic and Allow HTTP traffic from the internetConfigure storage, you can resize the Root volumegp3 is the default type and works for most usesio2 is the fastest and most expensive, for databases that need sub-millisecond latencysc1 and st1 are cheaper hard-disk types for rarely used data. They cannot be the root diskLaunch instance, open the Instances pageConnect to instance to see the instructionsyes to confirm the host fingerprint. SSH asks only onceubuntu@ip-172-31-13-146exit returns you to your own machinegit, python3, pip, boto3, jq, wget, ssh, vim, nano, tmuxaws commandEvery command has the same shape: aws <service> <command> [options]
| Part | Example | Meaning |
|---|---|---|
| Tool | aws |
The AWS command line |
| Service | ec2 |
Virtual servers |
| Command | describe-instances |
List your instances |
| Option | --output table |
Print a table instead of JSON |
s3, iam, lambda, stsstop-instancesaws s3 uses shell-like ls, cp, rm--region picks the data centre. us-east-1 is Virginia:Finding commands
/word searches and q quitsTab completes service and command namesUseful commands
Try it in class if there is time. Otherwise, try it at home
# 1. Who am I signed in as?
aws sts get-caller-identity
# 2. List your instances. Find InstanceId and State
aws ec2 describe-instances --output table
# 3. Stop yours, then run step 2 again
aws ec2 stop-instances --instance-ids i-...
# 4. Start it again
aws ec2 start-instances --instance-ids i-...
# 5. At home and done for the day? Terminate it
aws ec2 terminate-instances --instance-ids i-...stopping to stopped in about a minutessh commanddnf replaces apt, and what it installs is gone next sessionSteps 1 and 2: one instance running, one terminated. More commands
sudo apt updatesudo apt upgrade
-y answers yes to every prompt: sudo apt update && sudo apt upgrade -ysudo apt install
sudo apt install python3sudo apt install python3-pipsudo apt install jupyter-notebookscp (“secure copy”) moves files over SSH-i points to your key (the “identity file”)scp in a new local terminal, not on the instance:XXXXXX with your public DNS (Instances page):~: it means the home directoryls shows the file and python3 hello.py runs itssh commandt3.micro left on for a month: about $12 ($7.60 compute, $3.65 IP, $0.64 disk)jupyterssh -i "<your-key>.pem" ubuntu@<public-DNS> -L 8000:localhost:8888sudo apt update && sudo apt upgrade -ysudo apt install -y python3 python3-pip jupyter-notebookjupyter-notebook. python3-notebook lacks the jupyter commandwhich python3, which pip3, which jupyterjupyter notebookhttp://localhost:8000 and paste the token from the terminal
8888 to 8000print('Hello, DATASCI350!')Closing SSH stops Jupyter. tmux keeps it running after you disconnect, and tmux attach brings it back. The instance bills while it runs. More on tmux
scp: upload from your computer. For files that are not online, like your own datawget: download from the internet (e.g. GitHub) straight to the instancesudo apt install -y python3-numpy python3-pandas python3-matplotlib python3-seabornscp. On your local machine, create the dataset with this code, or download weather_data.py# weather_data.py
import pandas as pd
import numpy as np
import datetime
# Set seed for reproducibility
np.random.seed(42)
# Generate dates for the past 30 days
dates = pd.date_range(end=datetime.datetime.now(), periods=30).tolist()
dates = [d.strftime('%Y-%m-%d') for d in dates]
# Generate temperature data with some randomness
temp_high = np.random.normal(75, 8, 30)
temp_low = temp_high - np.random.uniform(10, 20, 30)
precipitation = np.random.exponential(0.5, 30)
humidity = np.random.normal(65, 10, 30)
# Create a structured dataset
weather_data = pd.DataFrame({
'date': dates,
'temp_high': temp_high,
'temp_low': temp_low,
'precipitation': precipitation,
'humidity': humidity
})
# Save to a text file
with open('weather_data.txt', 'w') as f:
f.write("# Weather data for the past 30 days\n")
f.write(weather_data.to_string(index=False))
print("Weather data saved to weather_data.txt")Run it on your local machine: python3 weather_data.py
It creates weather_data.txt, 30 days of weather data
Upload it from a local terminal:
scp -i <your-key>.pem weather_data.txt ubuntu@<public-DNS>:~/Check with ls on the instance
Method 2: wget. On the instance, download the analysis script:
wget https://raw.githubusercontent.com/danilofreire/datasci350/main/lectures/lecture-17/weather_analysis.py (one line)wget already downloaded it# weather_analysis.py
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from io import StringIO
# Read the weather data
with open('weather_data.txt', 'r') as f:
lines = f.readlines()
# Skip the header comment
data_str = ''.join(lines[1:])
df = pd.read_csv(StringIO(data_str), sep=r'\s+')
# Print basic statistics
print("Weather Data Analysis:")
print("=====================")
print(f"Number of days: {len(df)}")
print(f"Average high temperature: {df['temp_high'].mean():.1f}°F")
print(f"Average low temperature: {df['temp_low'].mean():.1f}°F")
print(f"Maximum temperature: {df['temp_high'].max():.1f}°F on {df.loc[df['temp_high'].idxmax(), 'date']}")
print(f"Minimum temperature: {df['temp_low'].min():.1f}°F on {df.loc[df['temp_low'].idxmin(), 'date']}")
print(f"Days with precipitation > 1 inch: {len(df[df['precipitation'] > 1])}")
# Create a visualisation
sns.set_style("whitegrid")
fig, ax1 = plt.subplots(figsize=(12, 6))
# Plot temperature range on the left axis
ax1.fill_between(df['date'], df['temp_low'], df['temp_high'], alpha=0.3, color='skyblue')
ax1.plot(df['date'], df['temp_high'], marker='o', color='red', label='High Temp')
ax1.plot(df['date'], df['temp_low'], marker='o', color='blue', label='Low Temp')
ax1.set_ylabel('Temperature (°F)')
# Add precipitation as bars on a second axis, on the right
ax2 = ax1.twinx()
ax2.bar(df['date'], df['precipitation'], alpha=0.3, color='navy', width=0.5, label='Precipitation')
ax2.set_ylabel('Precipitation (inches)', color='navy')
ax2.tick_params(axis='y', labelcolor='navy')
ax2.grid(False)
# One legend for both axes, and every fifth date on the x-axis
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
ax1.set_xticks(df['date'][::5])
ax1.tick_params(axis='x', labelrotation=45)
ax1.set_title('30-Day Weather Report: Temperature Range and Precipitation', fontsize=16)
fig.tight_layout()
# Save the figure
fig.savefig('weather_analysis.png')
print("Analysis complete. Results saved to 'weather_analysis.png'")weather_data.txt (from scp) and weather_analysis.py (from wget)python3 weather_analysis.py, or run it in Jupyterscp -i <your-key>.pem ubuntu@<public-DNS>:~/weather_analysis.png ./Recap: scp moves files between your computer and the instance. wget downloads from the internet to the instance
You’ve just completed a full data analysis workflow in the cloud 🎉
Data scientists use this same workflow for larger datasets and more complex analyses!
apt and ran Jupyter through a forwarded portscp and wgetaws command lineGET, POST, status codesrequests: does all this in three lines of Python.env file in Lecture 14Before then:
The final project is out: groups of four to five, due 8 December 2026. Pull data from a web API (the World Bank by default, or one you clear with me) and submit it as a Docker container. Start from the starter repository
chmod 400 on files in the Windows filesystem, so SSH refuses the keyActions, then Upload file..pem file. It arrives in /home/cloudshell-user.chmod 400 your-key.pem.ssh -i ... command the console gave you.