From d916a8008fbd672c1da488c1b1ec80489cee7e55 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 11 Mar 2025 19:33:11 +0200 Subject: [PATCH 01/44] Added terraform + ansible automated setup --- .gitignore | 14 + automated/README.md | 383 +++++++++++++++++++++++++ automated/infra/.terraform.lock.hcl | 21 ++ automated/infra/main.tf | 44 +++ automated/infra/provider.tf | 13 + automated/infra/terraform.tfvars | 5 + automated/infra/variables.tf | 24 ++ automated/playbooks/setup_vm_part1.yml | 285 ++++++++++++++++++ automated/playbooks/setup_vm_part2.yml | 261 +++++++++++++++++ 9 files changed, 1050 insertions(+) create mode 100644 automated/README.md create mode 100644 automated/infra/.terraform.lock.hcl create mode 100644 automated/infra/main.tf create mode 100644 automated/infra/provider.tf create mode 100644 automated/infra/terraform.tfvars create mode 100644 automated/infra/variables.tf create mode 100644 automated/playbooks/setup_vm_part1.yml create mode 100644 automated/playbooks/setup_vm_part2.yml diff --git a/.gitignore b/.gitignore index 30683a4..3e9297d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,16 @@ .DS_Store .ipynb_ckeckpoints + +## Terraform +**/.terraform/* +*.tfstate +*.tfstate.* +crash.log +crash.*.log +override.tf +override.tf.json +*_override.tf +*_override.tf.json +.terraform.tfstate.lock.info +*.terraformrc +terraform.rc diff --git a/automated/README.md b/automated/README.md new file mode 100644 index 0000000..ca8b899 --- /dev/null +++ b/automated/README.md @@ -0,0 +1,383 @@ +# ๐Ÿ’ป Automated DE GCP VM Setup - Terraform + Ansible + +This document contains instructions to set a largely automated VM setup on Google Cloud Platform. + +This setup has three main components, with the second and third components being largely automated: + +## Part 1: Setup of your local computer + +In this section we'll setup your local computer with some required software. This will include: +1. Installing some communication tools: Zoom, Slack +1. Creating some accounts: Github, Google Cloud Platform +1. Installing Visual Studio Code (VS Code) and some useful VS Code extensions +1. Installing and authenticating the GCP Command Line Tool (CLI): `gcloud`. You'll be using `gcloud` to create the connection between your local machine and the virtual machine you'll be creating! +1. Installing **Terraform** on your local computer. Terraform is an **Infrastructure as Code** (IaC) tool that you'll use to automate the creation of your VM! +1. Connect VS Code to your VM! + +## Part 2: Configuration of your Virtual Machine part 1 + +All parts of this section will happen on your VM. + +In this section you will: +1. Authenticate your VM with `gcloud` and for code that interacts with GCP Services +1. Run an `ansible` playbook. Ansible is another **Infrastructure as Code** tool that is used to automate the configuration and installation of software on computers. Perfect for fine tuning your VM. +1. Login to the GitHub CLI tool on your VM +1. Copy some **dotfiles** provided. **Dotfiles** are more settings that will enhance your terminal and developer experience. + +## Part 3: Configuration of your Virtual Machine part 2 + +All parts of this section will happen on your VM. + +In this section you will: +1. Run a second `ansible` playbook. This playbook will: + 1. Install some tools and frameworks (like python) + 1. Fork a repository with content + 1. Install python virtual environment for every challenge using poetry +1. You'll test your setup to make sure everything is working as intended ๐Ÿ‘Œ + +
+ +# 1๏ธโƒฃ Local Machine Setup + +We'll start with some communication tools that are widely used. + +## 1.1. Zoom + +Use existing fragment + +## 1.2. Slack + +Use existing fragment + +## 1.3. Github + +Use existing fragment + +## 1.4. Google Cloud Platform Setup + +Use existing fragment + +## 1.5. GCP API's + +Use existing fragment + +## โœจ 1.6. Download `gcloud` locally + + +
+๐ŸชŸ Windows + +A note about using windows terminal vs powershell here. + +Use the installer + +
+ +
+ +
+๐ŸŽ MacOS + +Use existing fragment from DS setup +
+ +
+ +
+๐Ÿง Linux + +Use existing fragment from DS setup +
+ +Cut Service account key here. + +## 1.7. Authorize local `gcloud` + +Use existing fragment from DS setup + +Add something about Windows for the installer + +- ๐ŸชŸ Windows: TODO - unsure. I assume it's the same +- ๐ŸŽ MacOS and ๐Ÿง Linux: `gcloud auth login` + +## 1.8. Visual Studio Code + +Use existing fragment + +## โœจ 1.9. Install Terraform Locally + +Terraform installer docs at this [link here](https://developer.hashicorp.com/terraform/install). + +
+๐ŸชŸ Windows + +Download binary and run + +
+ +
+ +
+๐ŸŽ MacOS + +```bash +brew tap hashicorp/tap +brew install hashicorp/tap/terraform +``` +
+ +
+ +
+๐Ÿง Linux + +```bash +wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list +sudo apt update && sudo apt install terraform +``` +
+ +## โœจ 1.10. Create your VM with Terraform + +Download files. This will be a `curl` from the repo or s3. + +For testing, copy the terraform files from `infra/` in the repo into `~/code//de-vm-setup`. Files to copy: +- `main.tf` +- `provider.tf` +- `variables.tf` +- `terraform.tfvars` + +Start with finding the username of your LOCAL computer, this is important to know and set. +- ๐ŸชŸ Windows: TODO - unsure. +- ๐ŸŽ MacOS: type `whoami` in the terminal +- ๐Ÿง Linux: type `whoami` in the terminal + +Update the values in `terraform.tfvars`: + +```bash +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" +``` + +It should look something similar to: + +```bash +project_id = "my-gcp-project" +region = "europe-west1" +zone = "europe-west1-b" +instance_name = "de-bootcamp-vm" +instance_user = "taylorswift" # the result of `whoami` +``` + +Make sure to save the `terraform.tfvars` file and run: + +```bash +terraform init + +terraform apply -auto-approve +``` + +## โœจ 1.11. Connect to your VM + +```bash +gcloud compute config-ssh +``` + +And connect via VS Code + +
+ +# 2๏ธโƒฃ Virtual Machine Part 1 + +## โœจ 2.1. Connect to VM and confirm `ansible` install + +In your VM's terminal type: + +```bash +ansible --version +``` + +Should look like: + +TODO: Add image asset + +## โœจ 2.2. Authenticate GCP CLI and ADC + +Use existing fragment for bulk of this. + +`gcloud` comes pre-installed on GCP Virtual Machines! + +We need to authenticate `gcloud` on our virtual machine so we can interact with GCP services from the command line and in our code. + +```bash +# gcloud login +gcloud auth login + +# ADC login +gcloud auth application-default login +``` + +Set your GCP project in `gcloud`: + +```bash +# Replace `PROJECT_ID` with the `ID` of your project +gcloud config set project PROJECT_ID +``` + +Confirm: + +```bash +gcloud config list +``` + +## โœจ 2.3. Run Ansible playbook 1 + +Download the first ansible playbook with the following: + +- `curl` from github or s3 to a specific target. Probably `~/playbooks` + +For testing, copy from the repo. + +Create the folder: + +```bash +mkdir ~/playbooks +``` + +And run with: + +```bash +cd ~/playbooks && ansible-playbook setup_vm_part1.yml +``` + +## 2.4. Github CLI Auth + +Use existing fragment + +Can't be easily automated without creating and copying SSH keys. + +## 2.5. Copy LW Dotfiles + +Use existing fragment + +Can't be easily automated, needs student input. + +Close all terminals and open a new terminal (I had to do it twice), it should look like: + +TODO: Add image asset +(Imagine basic zsh + OMZ) + +
+ +# 3๏ธโƒฃ Virtual Machine Part 2 + +In this section we'll run a second `ansible` playbook and check our setup + +## โœจ 3.1. Run Ansible playbook 2 + +Download the second ansible playbook with the following: + +- `curl` from github or s3 to a specific target. Probably `~/playbooks` + +For testing, copy and paste from repo. + +And run with: + +```bash +cd ~/playbooks && ansible-playbook setup_vm_part2.yml +``` + +Close all your terminals and open a new one. It should look like: + +TODO: Add image assets + +## โœจ 3.2. Check your Setup + +Things to check: + +Docker: +```bash +docker run hello-world +``` + +โ— If you get a permission error, SHUT DOWN your VM from the GCP console and turn it on again. Closing VS Code and opening it again is insufficient. + +TODO: Add image assets from existing fragment + +Minikube: + +```bash +# Start +minikube start + +# Get pods +kubectl get po -A + +# Stop +minikube delete --all +``` + +TODO: Add image assets from existing fragment + +Terraform: + +```bash +terraform --version +``` + +TODO: Add image assets from existing fragment + +Spark: + +```bash +spark-shell +``` + +TODO: Add image assets from existing fragment + +Pyenv: + +```bash +pyenv virtualenvs +# 3.12.8 +``` + +Python: + +```bash +python --version +# 3.12.8 +``` + +TODO: Add image assets from existing fragment + +Pipx: + +```bash +pipx list +``` + +TODO: Add image asset + +Data Engineering Challenges repo remotes: + +```bash +cd ~/code//data-engineering-challenges +git remote -v +``` + + +## 3.3. Run make install + +```bash +export GITHUB_USERNAME=`gh api user | jq -r '.login'` +echo $GITHUB_USERNAME + +cd ~/code/$GITHUB_USERNAME/data-engineering-challenges + +make install +``` diff --git a/automated/infra/.terraform.lock.hcl b/automated/infra/.terraform.lock.hcl new file mode 100644 index 0000000..4eaaa9e --- /dev/null +++ b/automated/infra/.terraform.lock.hcl @@ -0,0 +1,21 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/google" { + version = "6.24.0" + hashes = [ + "h1:Y9f/Q1dBiYpd8BvfSrkvSF3smM0SlHCoh66+KF0uzB8=", + "zh:0e7bb01149f50eabab725e8a0efadcb1cbfd7389f45adfb12e04f4f15a4fb5eb", + "zh:4172d07d61168e4246125e77ba5c67e96309783e2a8cd885cc51f3a73e7f14e2", + "zh:6952c1305d10b456170b2b7c34f0013ce4fd67161f6e7aa6daef61490da60252", + "zh:8ab7621209b352b12a0947865975ff83048c55a870a11306603b1b8052a3926b", + "zh:ba93efa1562d17f65001f8cce016ba903289ed985a7bec4b4d6339e3f52af3eb", + "zh:bc70ee209b816f74c9ffeaca9d3c85191ba8173f9f3f19425821a1ae9e4d47ea", + "zh:c9e8432861770f86a38a29c74d57cd5ecd7bec38fff0c719ed6136d34ae95ccd", + "zh:dfabe73e6de0cefa0b158f82647ca15325aa42bd0d8894ff82de02aed1c5814f", + "zh:e2798adc0d6edf9eb5e9ccbc2f4cd3914a0c76258e20690c86d7404490c10904", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f8884173e9334c3c408ecb869e44478061ffd1f23de6a204f5ab454a55ea9f12", + "zh:f8ecbc3274389f6fbb5ff5fc10f06db2390d02f50c0b35ef1c07f0203c341717", + ] +} diff --git a/automated/infra/main.tf b/automated/infra/main.tf new file mode 100644 index 0000000..773fb22 --- /dev/null +++ b/automated/infra/main.tf @@ -0,0 +1,44 @@ +resource "google_compute_instance" "my-instance" { + name = var.instance_name + machine_type = "e2-standard-4" + zone = var.zone + + boot_disk { + initialize_params { + image = "ubuntu-2204-jammy-v20250305" + size = 100 + type = "pd-balanced" + } + } + + network_interface { + network = "default" + access_config { + network_tier = "STANDARD" + } + } + + metadata_startup_script = <<-EOT +#!/bin/bash +set -e + +# Ensure the user exists +if ! id "${var.instance_user}" &>/dev/null; then + useradd -m -s /bin/bash ${var.instance_user} + echo "${var.instance_user} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers +fi + +# Ensure Ansible is installed +if ! command -v ansible &> /dev/null; then + apt update -y + apt install -y software-properties-common + add-apt-repository --yes --update ppa:ansible/ansible + apt install -y ansible +fi + +# Output Ansible version +sudo -u ${var.instance_user} ansible --version + +echo "Ansible installed successfully!" +EOT +} diff --git a/automated/infra/provider.tf b/automated/infra/provider.tf new file mode 100644 index 0000000..9e68fc4 --- /dev/null +++ b/automated/infra/provider.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "6.24.0" + } + } +} + +provider "google" { + project = var.project_id + region = var.region +} diff --git a/automated/infra/terraform.tfvars b/automated/infra/terraform.tfvars new file mode 100644 index 0000000..d8554b0 --- /dev/null +++ b/automated/infra/terraform.tfvars @@ -0,0 +1,5 @@ +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" diff --git a/automated/infra/variables.tf b/automated/infra/variables.tf new file mode 100644 index 0000000..0566410 --- /dev/null +++ b/automated/infra/variables.tf @@ -0,0 +1,24 @@ +variable "project_id" { + description = "GCP Project ID" + type = string +} + +variable "region" { + description = "GCP Region" + type = string +} + +variable "zone" { + description = "GCP Zone" + type = string +} + +variable "instance_name" { + description = "VM name" + type = string +} + +variable "instance_user" { + description = "Instance username" + type = string +} diff --git a/automated/playbooks/setup_vm_part1.yml b/automated/playbooks/setup_vm_part1.yml new file mode 100644 index 0000000..3495a8d --- /dev/null +++ b/automated/playbooks/setup_vm_part1.yml @@ -0,0 +1,285 @@ +--- +- name: Setup VM Part 1 - Update VM with non-dependant software + hosts: localhost + connection: local + become: true + vars: + my_user: "{{ lookup('env', 'USER') }}" + architecture: "{{ 'amd64' if ansible_architecture == 'x86_64' else ansible_architecture }}" + tasks: + - name: Debug Variables + debug: + msg: + - "Running playbook as the user: {{ my_user }}" + - "Running Ubuntu version: {{ ansible_distribution_release }}" + - "On architecture: {{ architecture }}" + + - name: Install apt packages + block: + - name: Check last apt update time + stat: + path: /var/lib/apt/periodic/update-success-stamp + register: apt_stamp + tags: apt + + - name: Update apt package list if update >24 hours ago + apt: + update_cache: true + become: true + when: apt_stamp.stat.exists == false or (ansible_date_time.epoch | int - apt_stamp.stat.mtime | int) > 86400 + tags: apt + + - name: Install required apt packages + apt: + name: + - vim + - tmux + - tree + - git + - ca-certificates + - curl + - jq + - unzip + - zsh + - apt-transport-https + - gnupg + - software-properties-common + - direnv + - sqlite3 + - make + - postgresql + - postgresql-contrib + - build-essential + - libssl-dev + - zlib1g-dev + - libbz2-dev + - libreadline-dev + - libsqlite3-dev + - wget + - llvm + - libncursesw5-dev + - xz-utils + - tk-dev + - libxml2-dev + - libxmlsec1-dev + - libffi-dev + - liblzma-dev + - gcc + - default-mysql-server + - default-libmysqlclient-dev + - libpython3-dev + - openjdk-8-jdk-headless + state: present + become: true + tags: apt + + - name: Set zsh as default shell + user: + name: "{{ my_user }}" + shell: /usr/bin/zsh + + - name: Install Oh My Zsh + block: + - name: Check if Oh My Zsh is installed + stat: + path: "/home/{{ my_user }}/.oh-my-zsh" + register: omz_check + tags: omz + + - name: Install Oh My Zsh from repo + shell: | + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + become_user: "{{ my_user }}" + when: not omz_check.stat.exists + tags: omz + + - name: Install Docker + block: + - name: Check if Docker is installed + stat: + path: /usr/bin/docker + register: docker_check + tags: docker + + - name: Add Docker GPG key + apt_key: + url: "https://download.docker.com/linux/ubuntu/gpg" + keyring: "/etc/apt/keyrings/docker.gpg" + state: present + when: not docker_check.stat.exists + tags: docker + + - name: Add Docker APT repository + apt_repository: + repo: "deb [arch={{ architecture }} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" + state: present + when: not docker_check.stat.exists + tags: docker + + - name: Update APT cache + apt: + update_cache: true + when: not docker_check.stat.exists + + - name: Install Docker packages + apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + state: present + when: not docker_check.stat.exists + + - name: Ensure docker group exists + group: + name: docker + state: present + tags: docker + + - name: Add user to the docker group + user: + name: "{{ my_user }}" + groups: docker + append: true + tags: docker + + - name: Authenticate gcloud with Docker + block: + - name: Check if Docker authentication config exists + stat: + path: "/home/{{ my_user }}/.docker/config.json" + register: docker_config + tags: docker + + - name: Check if gcloud is authenticated with Docker + shell: "grep -q 'gcr.io' /home/{{ my_user }}/.docker/config.json" + become_user: "{{ my_user }}" + register: gcloud_docker_check + ignore_errors: true + changed_when: false + when: docker_config.stat.exists + tags: docker + + - name: Authenticate gcloud with Docker + shell: | + gcloud auth configure-docker + become_user: "{{ my_user }}" + when: not docker_config.stat.exists or gcloud_docker_check.rc != 0 + tags: docker + + - name: Enable GCP Artifact Registry API + block: + - name: Check if GCP Artifact Registry API is enabled + shell: | + gcloud services list --enabled --format="value(config.name)" | grep -q "^artifactregistry.googleapis.com$" + become_user: "{{ my_user }}" + register: gcp_ar_check + ignore_errors: true + changed_when: false + tags: gcp_ar + + - name: Enable GCP Artifact Registry API + shell: | + gcloud services enable artifactregistry.googleapis.com + become_user: "{{ my_user }}" + when: gcp_ar_check.rc != 0 + tags: gcp_ar + + - name: Install kubectl + block: + - name: Check if kubectl is installed + stat: + path: /usr/local/bin/kubectl + register: kubectl_check + tags: kubectl + + - name: Download kubectl binary and add to path + get_url: + url: "https://dl.k8s.io/release/{{ lookup('url', 'https://dl.k8s.io/release/stable.txt') }}/bin/linux/amd64/kubectl" + dest: "/usr/local/bin/kubectl" + mode: "0755" + when: not kubectl_check.stat.exists + tags: kubectl + + - name: Install minikube + block: + - name: Chech if minikube is installed + stat: + path: /usr/local/bin/minikube + register: minikube_check + tags: minikube + + - name: Download minikube binary and add to path + get_url: + url: "https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64" + dest: "/usr/local/bin/minikube" + mode: "0755" + when: not minikube_check.stat.exists + tags: minikube + + - name: Install terraform + block: + - name: Check if terraform is installed + stat: + path: /usr/bin/terraform + register: terraform_check + tags: terraform + + - name: Add HashiCorp GPG key + apt_key: + url: "https://apt.releases.hashicorp.com/gpg" + keyring: "/usr/share/keyrings/hashicorp-archive-keyring.gpg" + state: present + tags: terraform + + - name: Add HashiCorp GPG repository + apt_repository: + repo: "deb [arch={{ architecture }} signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com {{ ansible_distribution_release }} main" + state: present + when: not terraform_check.stat.exists + tags: terraform + + - name: Update APT cache + apt: + update_cache: true + when: not terraform_check.stat.exists + tags: terraform + + - name: Install terraform + apt: + name: terraform + state: present + when: not terraform_check.stat.exists + tags: terraform + + - name: Install Github CLI + block: + - name: Check if Github CLI is installed + stat: + path: /usr/bin/gh + register: gh_check + tags: gh_cli + + - name: Add GitHub CLI GPG key + get_url: + url: "https://cli.github.com/packages/githubcli-archive-keyring.gpg" + dest: "/usr/share/keyrings/githubcli-archive-keyring.gpg" + mode: "0644" + when: not gh_check.stat.exists + tags: gh_cli + + - name: Add GitHub CLI APT repository + apt_repository: + repo: "deb [arch={{ architecture }} signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" + state: present + when: not gh_check.stat.exists + tags: gh_cli + + - name: Install GitHub CLI + apt: + name: gh + state: present + when: not gh_check.stat.exists + tags: gh_cli diff --git a/automated/playbooks/setup_vm_part2.yml b/automated/playbooks/setup_vm_part2.yml new file mode 100644 index 0000000..1fcef00 --- /dev/null +++ b/automated/playbooks/setup_vm_part2.yml @@ -0,0 +1,261 @@ +--- +- name: Setup VM Part 2 - Update VM with dependant software + hosts: localhost + connection: local + become: true + vars: + my_user: "{{ lookup('env', 'USER') }}" + architecture: "{{ 'amd64' if ansible_architecture == 'x86_64' else ansible_architecture }}" + ansible_shell_executable: /usr/bin/zsh + tasks: + - name: Debug Variables + debug: + msg: + - "Running playbook as the user: {{ my_user }}" + - "Running Ubuntu version: {{ ansible_distribution_release }}" + - "On architecture: {{ architecture }}" + + - name: Install Spark + block: + - name: Check if Spark is installed + stat: + path: "/home/{{ my_user }}/spark/spark-3.5.3-bin-hadoop3" + register: spark_installed + tags: spark + + - name: Install Spark (Async) + shell: | + wget -q https://archive.apache.org/dist/spark/spark-3.5.3/spark-3.5.3-bin-hadoop3.tgz -O /tmp/spark.tgz + mkdir -p ~/spark && tar -xzf /tmp/spark.tgz -C ~/spark + become_user: "{{ my_user }}" + when: not spark_installed.stat.exists + async: 1800 # Runs in the background for up to 30 minutes + poll: 0 # Continue running other tasks + register: spark_async + tags: spark + + - name: Debug Spark async job ID + debug: + msg: "Spark async job ID: {{ spark_async.ansible_job_id }}" + + - name: Add .zshrc plugins - direnv, pyenv, gcloud + lineinfile: + path: "~/.zshrc" + regexp: "plugins=" + line: "plugins=(git gitfast last-working-dir common-aliases zsh-syntax-highlighting history-substring-search pyenv ssh-agent direnv gcloud)" + create: true + become_user: "{{ my_user }}" + tags: zshrc + + - name: Add spark, pyenv, pipx to path + blockinfile: + path: "~/.zshrc" + block: | + # Spark + export SPARK_HOME=$HOME/spark/spark-3.5.3-bin-hadoop3 + export PATH=$PATH:$SPARK_HOME/bin + + # pyenv + export PYENV_ROOT="$HOME/.pyenv" + [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" + eval "$(pyenv init - zsh)" + + # pipx + export PATH="$HOME/.local/bin:$PATH" + marker: "# {mark} ANSIBLE CREATED BLOCK: path vars" + create: true + become_user: "{{ my_user }}" + tags: zshrc + + - name: Create direnv Poetry Hook + blockinfile: + path: "~/.direnvrc" + block: | + layout_poetry() { + if [[ ! -f pyproject.toml ]]; then + log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.' + exit 2 + fi + # create venv if it doesn't exist + poetry run true + + export VIRTUAL_ENV=$(poetry env info --path) + export POETRY_ACTIVE=1 + PATH_add "$VIRTUAL_ENV/bin" + } + marker: "# {mark} ANSIBLE CREATED BLOCK: layout_poetry" + create: true + mode: "0644" + become_user: "{{ my_user }}" + + - name: Update VS Code python interpreter + lineinfile: + path: "~/.vscode-server/data/Machine/settings.json" + regexp: ' "python.defaultInterpreterPath": "~/.pyenv/shims/python",' + line: ' "python.defaultInterpreterPath": ".venv/bin/python",' + create: true + become_user: "{{ my_user }}" + + - name: Insall pyenv + block: + - name: Check if pyenv is installed + stat: + path: "/home/{{ my_user }}/.pyenv" + register: pyenv_installed + tags: pyenv + + - name: Install pyenv + git: + repo: "https://github.com/pyenv/pyenv.git" + dest: "/home/{{ my_user }}/.pyenv" + become_user: "{{ my_user }}" + when: not pyenv_installed.stat.exists + tags: pyenv + + - name: Check if pyenv-virtualenv is installed + stat: + path: "/home/{{ my_user }}/.pyenv/plugins/pyenv-virtualenv" + register: pyenv_virtualenv_installed + tags: pyenv + + - name: Install pyenv-virtualenv + git: + repo: "https://github.com/pyenv/pyenv-virtualenv.git" + dest: "/home/{{ my_user }}/.pyenv/plugins/pyenv-virtualenv" + become_user: "{{ my_user }}" + when: not pyenv_virtualenv_installed.stat.exists + tags: pyenv + + - name: Install Python 3.12.8 using pyenv + block: + - name: Check if Python 3.12.8 is installed + command: > + zsh -c 'export PYENV_ROOT="$HOME/.pyenv"; + export PATH="$PYENV_ROOT/bin:$PATH"; + eval "$(pyenv init --path)"; + pyenv versions --bare' + become_user: "{{ my_user }}" + register: python_installed + changed_when: false + tags: python + + - name: Install Python 3.12.8 with pyenv + command: > + zsh -c 'export PYENV_ROOT="$HOME/.pyenv"; + export PATH="$PYENV_ROOT/bin:$PATH"; + eval "$(pyenv init --path)"; + pyenv install 3.12.8 && pyenv global 3.12.8' + become_user: "{{ my_user }}" + when: "'3.12.8' not in python_installed.stdout" + tags: python + + - name: Install pipx + block: + - name: Check if pipx is installed + stat: + path: "/home/{{ my_user }}/.local/bin/pipx" + register: pipx_installed + tags: pipx + + - name: Install pipx + shell: | + source ~/.zshrc + pip install --upgrade pip + python -m ensurepip --default-pip + python -m pip install --user pipx + python -m pipx ensurepath + become_user: "{{ my_user }}" + when: not pipx_installed.stat.exists + tags: pipx + + - name: Install pipx packages + block: + - name: Check installed pipx packages + command: "/home/{{ my_user }}/.local/bin/pipx list" + become_user: "{{ my_user }}" + register: pipx_list + changed_when: false + tags: pipx_packages + + - name: Install missing pipx packages - poetry, tldr, ruff + command: "/home/{{ my_user }}/.local/bin/pipx install {{ item }}" + loop: + - poetry + - tldr + - ruff + become_user: "{{ my_user }}" + when: "item not in pipx_list.stdout" + tags: pipx_packages + + - name: Ensure Poetry venv is set to in-project + shell: | + source ~/.zshrc + poetry config virtualenvs.in-project true + become_user: "{{ my_user }}" + changed_when: false + + - name: Fork and clone lewagon/data-engineering-challenges + block: + - name: Get GitHub Username using gh CLI + command: gh api user --jq '.login' + become_user: "{{ my_user }}" + register: github_username + changed_when: false + tags: github + + - name: Check if repository already exists + stat: + path: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" + register: repo_exists + tags: github + + - name: Fork repository if not already forked + command: gh repo fork lewagon/data-engineering-challenges --remote + become_user: "{{ my_user }}" + when: not repo_exists.stat.exists + tags: github + + - name: Clone repository if not already cloned + git: + repo: "git@github.com:{{ github_username.stdout }}/data-engineering-challenges.git" + dest: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" + clone: true + update: false + accept_hostkey: true + become_user: "{{ my_user }}" + when: not repo_exists.stat.exists + tags: github + + - name: Check upstream remote + command: git remote -v + args: + chdir: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" + become_user: "{{ my_user }}" + register: existing_remotes + changed_when: false + tags: github + + - name: Add upstream remote + command: git remote add upstream git@github.com:lewagon/data-engineering-challenges.git + args: + chdir: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" + become_user: "{{ my_user }}" + when: "'upstream' not in existing_remotes.stdout" + tags: github + + - name: Wait for Spark installation to complete - This can take a while. Spark is big! 1 Retry = 30 seconds + async_status: + jid: "{{ spark_async.ansible_job_id }}" + become_user: "{{ my_user }}" + register: spark_result + until: spark_result.finished + retries: 60 + delay: 30 + when: spark_async.ansible_job_id is defined + tags: spark + + # - name: Create Poetry environments + # shell: | + # GITHUB_USERNAME=$(gh api user | jq -r '.login') + # cd ~/code/$GITHUB_USERNAME/data-engineering-challenges && make install + # become_user: "{{ my_user }}" From fef8cafc8a22a1ee54cdb6ec6b76785fc7ac659f Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 13:16:03 +0200 Subject: [PATCH 02/44] ansible setup_vm_part2.yml: added idempotency to forking de-challenges --- .../playbooks/setup_vm_part1.yml | 0 .../playbooks/setup_vm_part2.yml | 33 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) rename automated/{ => vm-ansible-setup}/playbooks/setup_vm_part1.yml (100%) rename automated/{ => vm-ansible-setup}/playbooks/setup_vm_part2.yml (89%) diff --git a/automated/playbooks/setup_vm_part1.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml similarity index 100% rename from automated/playbooks/setup_vm_part1.yml rename to automated/vm-ansible-setup/playbooks/setup_vm_part1.yml diff --git a/automated/playbooks/setup_vm_part2.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml similarity index 89% rename from automated/playbooks/setup_vm_part2.yml rename to automated/vm-ansible-setup/playbooks/setup_vm_part2.yml index 1fcef00..6578552 100644 --- a/automated/playbooks/setup_vm_part2.yml +++ b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml @@ -29,7 +29,7 @@ mkdir -p ~/spark && tar -xzf /tmp/spark.tgz -C ~/spark become_user: "{{ my_user }}" when: not spark_installed.stat.exists - async: 1800 # Runs in the background for up to 30 minutes + async: 3600 # Runs in the background for up to 60 minutes poll: 0 # Continue running other tasks register: spark_async tags: spark @@ -37,6 +37,7 @@ - name: Debug Spark async job ID debug: msg: "Spark async job ID: {{ spark_async.ansible_job_id }}" + when: not spark_installed.stat.exists - name: Add .zshrc plugins - direnv, pyenv, gcloud lineinfile: @@ -203,19 +204,27 @@ changed_when: false tags: github - - name: Check if repository already exists - stat: - path: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" - register: repo_exists + - name: Check if lewagon/data-engineering-challenges has been forked + command: gh repo list --json nameWithOwner --jq '.[] | select(.nameWithOwner == "{{ github_username.stdout }}/data-engineering-challenges")' + become_user: "{{ my_user }}" + register: fork_exists + changed_when: false + failed_when: false tags: github - - name: Fork repository if not already forked + - name: Fork lewagon/data-engineering-challenges repo command: gh repo fork lewagon/data-engineering-challenges --remote become_user: "{{ my_user }}" - when: not repo_exists.stat.exists + when: not fork_exists.stdout | trim == "" + tags: github + + - name: Check if ~/code//data-engineering-challenges exist on the VM + stat: + path: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" + register: local_repo_exists tags: github - - name: Clone repository if not already cloned + - name: Clone data-engineering-challenges to VM git: repo: "git@github.com:{{ github_username.stdout }}/data-engineering-challenges.git" dest: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" @@ -223,10 +232,10 @@ update: false accept_hostkey: true become_user: "{{ my_user }}" - when: not repo_exists.stat.exists + when: not local_repo_exists.stat.exists tags: github - - name: Check upstream remote + - name: Check data-engineering-challenges git remotes command: git remote -v args: chdir: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" @@ -235,7 +244,7 @@ changed_when: false tags: github - - name: Add upstream remote + - name: Add upstream remote to data-engineering-challenges command: git remote add upstream git@github.com:lewagon/data-engineering-challenges.git args: chdir: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" @@ -249,7 +258,7 @@ become_user: "{{ my_user }}" register: spark_result until: spark_result.finished - retries: 60 + retries: 150 delay: 30 when: spark_async.ansible_job_id is defined tags: spark From b8d3b1279120a82f9c9381a1117514c27cd56563 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 14:09:01 +0200 Subject: [PATCH 03/44] ansible, setup_vm_part2.yml: more idempotency and redundancy on de-challenges fork --- .../playbooks/setup_vm_part2.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml index 6578552..798f67e 100644 --- a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml +++ b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml @@ -215,10 +215,20 @@ - name: Fork lewagon/data-engineering-challenges repo command: gh repo fork lewagon/data-engineering-challenges --remote become_user: "{{ my_user }}" - when: not fork_exists.stdout | trim == "" + when: fork_exists.stdout | trim == "" tags: github - - name: Check if ~/code//data-engineering-challenges exist on the VM + - name: Wait for GitHub fork to be fully available + command: "gh repo view {{ github_username.stdout }}/data-engineering-challenges" + become_user: "{{ my_user }}" + register: fork_ready + retries: 10 + delay: 10 + until: fork_ready.rc == 0 + changed_when: false + tags: github + + - name: Check if ~/code/{{ github_username.stdout }}/data-engineering-challenges exist on the VM stat: path: "/home/{{ my_user }}/code/{{ github_username.stdout }}/data-engineering-challenges" register: local_repo_exists @@ -252,7 +262,7 @@ when: "'upstream' not in existing_remotes.stdout" tags: github - - name: Wait for Spark installation to complete - This can take a while. Spark is big! 1 Retry = 30 seconds + - name: Wait for Spark installation to complete - Can take a while. 1 Retry = 30 seconds async_status: jid: "{{ spark_async.ansible_job_id }}" become_user: "{{ my_user }}" From af9d4abe045ab2a80472d46ca2f92c6048cba67a Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 14:56:22 +0200 Subject: [PATCH 04/44] ansible, setup_vm_part2.yml: added remote VS Code extensions check and download --- .../playbooks/setup_vm_part2.yml | 48 +++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml index 798f67e..33d59bc 100644 --- a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml +++ b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml @@ -89,15 +89,47 @@ mode: "0644" become_user: "{{ my_user }}" - - name: Update VS Code python interpreter - lineinfile: - path: "~/.vscode-server/data/Machine/settings.json" - regexp: ' "python.defaultInterpreterPath": "~/.pyenv/shims/python",' - line: ' "python.defaultInterpreterPath": ".venv/bin/python",' - create: true - become_user: "{{ my_user }}" + - name: VS Code Config + block: + - name: Detect VS Code CLI path + shell: | + find /home/{{ my_user }}/.vscode-server/cli/servers/ -maxdepth 5 -type f -name "code" | head -n 1 + register: vscode_cli_path + changed_when: false + tags: vscode + + - name: Check installed VS Code extensions + shell: "{{ vscode_cli_path.stdout }} --list-extensions" + register: vscode_installed_extensions + changed_when: false + when: vscode_cli_path.stdout | length > 0 + tags: vscode + + - name: Install missing VS Code extensions + shell: "{{ vscode_cli_path.stdout }} --install-extension {{ item }}" + loop: + - ms-vscode.sublime-keybindings + - emmanuelbeziat.vscode-great-icons + - ms-python.python + - KevinRose.vsc-python-indent + - ms-python.vscode-pylance + - redhat.vscode-yaml + - ms-azuretools.vscode-docker + - tamasfe.even-better-toml + when: vscode_cli_path.stdout | length > 0 and vscode_installed_extensions.stdout is defined and (item not in vscode_installed_extensions.stdout) + become_user: "{{ my_user }}" + tags: vscode + + - name: Update VS Code python interpreter + lineinfile: + path: "~/.vscode-server/data/Machine/settings.json" + regexp: ' "python.defaultInterpreterPath": "~/.pyenv/shims/python",' + line: ' "python.defaultInterpreterPath": ".venv/bin/python",' + create: true + become_user: "{{ my_user }}" + tags: vscode - - name: Insall pyenv + - name: Install pyenv and pyenv-virtualenv block: - name: Check if pyenv is installed stat: From 6920796ddf37070d49159dff6173c95df539504a Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 14:56:36 +0200 Subject: [PATCH 05/44] added ansible config files --- automated/vm-ansible-setup/ansible.cfg | 5 +++++ automated/vm-ansible-setup/hosts | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 automated/vm-ansible-setup/ansible.cfg create mode 100644 automated/vm-ansible-setup/hosts diff --git a/automated/vm-ansible-setup/ansible.cfg b/automated/vm-ansible-setup/ansible.cfg new file mode 100644 index 0000000..39517a9 --- /dev/null +++ b/automated/vm-ansible-setup/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +inventory = hosts +host_key_checking = False +retry_files_enabled = False +interpreter_python = auto diff --git a/automated/vm-ansible-setup/hosts b/automated/vm-ansible-setup/hosts new file mode 100644 index 0000000..13cfabe --- /dev/null +++ b/automated/vm-ansible-setup/hosts @@ -0,0 +1,2 @@ +[local] +localhost ansible_connection=local From f9971b40548802a07796236e2928645db5227547 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 16:24:19 +0200 Subject: [PATCH 06/44] typo corrections in ansible playbooks --- .../vm-ansible-setup/playbooks/setup_vm_part1.yml | 2 +- .../vm-ansible-setup/playbooks/setup_vm_part2.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml index 3495a8d..489d2be 100644 --- a/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml +++ b/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml @@ -205,7 +205,7 @@ - name: Install minikube block: - - name: Chech if minikube is installed + - name: Check if minikube is installed stat: path: /usr/local/bin/minikube register: minikube_check diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml index 33d59bc..fd3fe25 100644 --- a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml +++ b/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml @@ -48,7 +48,7 @@ become_user: "{{ my_user }}" tags: zshrc - - name: Add spark, pyenv, pipx to path + - name: Add Spark, pyenv, pipx to PATH blockinfile: path: "~/.zshrc" block: | @@ -68,7 +68,7 @@ become_user: "{{ my_user }}" tags: zshrc - - name: Create direnv Poetry Hook + - name: Create direnv Poetry function blockinfile: path: "~/.direnvrc" block: | @@ -120,7 +120,7 @@ become_user: "{{ my_user }}" tags: vscode - - name: Update VS Code python interpreter + - name: Update VS Code python interpreter to poetry venv lineinfile: path: "~/.vscode-server/data/Machine/settings.json" regexp: ' "python.defaultInterpreterPath": "~/.pyenv/shims/python",' @@ -294,14 +294,14 @@ when: "'upstream' not in existing_remotes.stdout" tags: github - - name: Wait for Spark installation to complete - Can take a while. 1 Retry = 30 seconds + - name: Wait for Spark installation to complete - Can take a while. 1 Retry = 60s async_status: jid: "{{ spark_async.ansible_job_id }}" become_user: "{{ my_user }}" register: spark_result until: spark_result.finished retries: 150 - delay: 30 + delay: 60 when: spark_async.ansible_job_id is defined tags: spark From f00bae1f9cab492e02472c1197b0024841b8f69b Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 16:26:31 +0200 Subject: [PATCH 07/44] updated curl links --- automated/README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/automated/README.md b/automated/README.md index ca8b899..f6f74f7 100644 --- a/automated/README.md +++ b/automated/README.md @@ -140,7 +140,7 @@ sudo apt update && sudo apt install terraform ## โœจ 1.10. Create your VM with Terraform -Download files. This will be a `curl` from the repo or s3. +Download files. This will be a `curl` from the repo. For testing, copy the terraform files from `infra/` in the repo into `~/code//de-vm-setup`. Files to copy: - `main.tf` @@ -238,21 +238,26 @@ gcloud config list Download the first ansible playbook with the following: +```bash +# TODO: Update if merged +mkdir -p ~/vm-ansible-setup/playbooks +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml +``` + - `curl` from github or s3 to a specific target. Probably `~/playbooks` -For testing, copy from the repo. -Create the folder: +And run with: ```bash -mkdir ~/playbooks +cd ~/vm-ansible-setup && ansible-playbook playbooks/setup_vm_part1.yml ``` -And run with: +Close all your terminals and open a new one. It should look like: -```bash -cd ~/playbooks && ansible-playbook setup_vm_part1.yml -``` +TODO: Add image assets ## 2.4. Github CLI Auth @@ -281,19 +286,19 @@ In this section we'll run a second `ansible` playbook and check our setup Download the second ansible playbook with the following: -- `curl` from github or s3 to a specific target. Probably `~/playbooks` - -For testing, copy and paste from repo. +```bash +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml +``` And run with: ```bash -cd ~/playbooks && ansible-playbook setup_vm_part2.yml +cd ~/vm-ansible-setup && ansible-playbook playbooks/setup_vm_part2.yml ``` -Close all your terminals and open a new one. It should look like: +Once the playbook has finished, we need to completely SHUT DOWN your VM from the GCP console at [this link here](https://console.cloud.google.com/compute/instances?). Closing your VS Code and opening it again is not sufficient. -TODO: Add image assets +TODO: add image assets ## โœจ 3.2. Check your Setup From 57dae029aae7dc09c9f1243ca45c9565484ea997 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 16:27:13 +0200 Subject: [PATCH 08/44] updated network tier in tf.main from STANDARD -> PREMIUM --- automated/infra/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automated/infra/main.tf b/automated/infra/main.tf index 773fb22..8d88935 100644 --- a/automated/infra/main.tf +++ b/automated/infra/main.tf @@ -14,7 +14,7 @@ resource "google_compute_instance" "my-instance" { network_interface { network = "default" access_config { - network_tier = "STANDARD" + # assigns an ephemeral external IP address } } From 097b1f6f4263fb7fecc1a74c73aa9b5e4ca8258c Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 13 Mar 2025 16:31:26 +0200 Subject: [PATCH 09/44] automated/readme update --- automated/README.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/automated/README.md b/automated/README.md index f6f74f7..8b1d86a 100644 --- a/automated/README.md +++ b/automated/README.md @@ -43,23 +43,23 @@ We'll start with some communication tools that are widely used. ## 1.1. Zoom -Use existing fragment +Use existing partial ## 1.2. Slack -Use existing fragment +Use existing partial ## 1.3. Github -Use existing fragment +Use existing partial ## 1.4. Google Cloud Platform Setup -Use existing fragment +Use existing partial ## 1.5. GCP API's -Use existing fragment +Use existing partial ## โœจ 1.6. Download `gcloud` locally @@ -78,7 +78,7 @@ Use the installer
๐ŸŽ MacOS -Use existing fragment from DS setup +Use existing partial from DS setup

@@ -86,14 +86,14 @@ Use existing fragment from DS setup
๐Ÿง Linux -Use existing fragment from DS setup +Use existing partial from DS setup
Cut Service account key here. ## 1.7. Authorize local `gcloud` -Use existing fragment from DS setup +Use existing partial from DS setup Add something about Windows for the installer @@ -102,7 +102,7 @@ Add something about Windows for the installer ## 1.8. Visual Studio Code -Use existing fragment +Use existing partial ## โœจ 1.9. Install Terraform Locally @@ -207,7 +207,7 @@ TODO: Add image asset ## โœจ 2.2. Authenticate GCP CLI and ADC -Use existing fragment for bulk of this. +Use existing partial for bulk of this. `gcloud` comes pre-installed on GCP Virtual Machines! @@ -246,9 +246,6 @@ curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/da curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml ``` -- `curl` from github or s3 to a specific target. Probably `~/playbooks` - - And run with: ```bash @@ -261,13 +258,13 @@ TODO: Add image assets ## 2.4. Github CLI Auth -Use existing fragment +Use existing partial Can't be easily automated without creating and copying SSH keys. ## 2.5. Copy LW Dotfiles -Use existing fragment +Use existing partial Can't be easily automated, needs student input. @@ -311,7 +308,7 @@ docker run hello-world โ— If you get a permission error, SHUT DOWN your VM from the GCP console and turn it on again. Closing VS Code and opening it again is insufficient. -TODO: Add image assets from existing fragment +TODO: Add image assets from existing partial Minikube: @@ -326,7 +323,7 @@ kubectl get po -A minikube delete --all ``` -TODO: Add image assets from existing fragment +TODO: Add image assets from existing partial Terraform: @@ -334,7 +331,7 @@ Terraform: terraform --version ``` -TODO: Add image assets from existing fragment +TODO: Add image assets from existing partial Spark: @@ -342,7 +339,7 @@ Spark: spark-shell ``` -TODO: Add image assets from existing fragment +TODO: Add image assets from existing partial Pyenv: @@ -358,7 +355,7 @@ python --version # 3.12.8 ``` -TODO: Add image assets from existing fragment +TODO: Add image assets from existing partial Pipx: From 30faa5562888b1698bd1764c7b93a77854ac253c Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Fri, 14 Mar 2025 14:24:51 +0200 Subject: [PATCH 10/44] renamed automated to automation --- {automated => automation}/README.md | 10 +++++----- {automated => automation}/infra/.terraform.lock.hcl | 0 {automated => automation}/infra/main.tf | 0 {automated => automation}/infra/provider.tf | 0 {automated => automation}/infra/terraform.tfvars | 0 {automated => automation}/infra/variables.tf | 0 {automated => automation}/vm-ansible-setup/ansible.cfg | 0 {automated => automation}/vm-ansible-setup/hosts | 0 .../vm-ansible-setup/playbooks/setup_vm_part1.yml | 0 .../vm-ansible-setup/playbooks/setup_vm_part2.yml | 0 10 files changed, 5 insertions(+), 5 deletions(-) rename {automated => automation}/README.md (96%) rename {automated => automation}/infra/.terraform.lock.hcl (100%) rename {automated => automation}/infra/main.tf (100%) rename {automated => automation}/infra/provider.tf (100%) rename {automated => automation}/infra/terraform.tfvars (100%) rename {automated => automation}/infra/variables.tf (100%) rename {automated => automation}/vm-ansible-setup/ansible.cfg (100%) rename {automated => automation}/vm-ansible-setup/hosts (100%) rename {automated => automation}/vm-ansible-setup/playbooks/setup_vm_part1.yml (100%) rename {automated => automation}/vm-ansible-setup/playbooks/setup_vm_part2.yml (100%) diff --git a/automated/README.md b/automation/README.md similarity index 96% rename from automated/README.md rename to automation/README.md index 8b1d86a..3236c27 100644 --- a/automated/README.md +++ b/automation/README.md @@ -241,9 +241,9 @@ Download the first ansible playbook with the following: ```bash # TODO: Update if merged mkdir -p ~/vm-ansible-setup/playbooks -curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/ansible.cfg -curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/hosts -curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml ``` And run with: @@ -260,7 +260,7 @@ TODO: Add image assets Use existing partial -Can't be easily automated without creating and copying SSH keys. +Can't be easily automated without creating & copying SSH keys, and generating GitHub PAT tokens. ## 2.5. Copy LW Dotfiles @@ -284,7 +284,7 @@ In this section we'll run a second `ansible` playbook and check our setup Download the second ansible playbook with the following: ```bash -curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml ``` And run with: diff --git a/automated/infra/.terraform.lock.hcl b/automation/infra/.terraform.lock.hcl similarity index 100% rename from automated/infra/.terraform.lock.hcl rename to automation/infra/.terraform.lock.hcl diff --git a/automated/infra/main.tf b/automation/infra/main.tf similarity index 100% rename from automated/infra/main.tf rename to automation/infra/main.tf diff --git a/automated/infra/provider.tf b/automation/infra/provider.tf similarity index 100% rename from automated/infra/provider.tf rename to automation/infra/provider.tf diff --git a/automated/infra/terraform.tfvars b/automation/infra/terraform.tfvars similarity index 100% rename from automated/infra/terraform.tfvars rename to automation/infra/terraform.tfvars diff --git a/automated/infra/variables.tf b/automation/infra/variables.tf similarity index 100% rename from automated/infra/variables.tf rename to automation/infra/variables.tf diff --git a/automated/vm-ansible-setup/ansible.cfg b/automation/vm-ansible-setup/ansible.cfg similarity index 100% rename from automated/vm-ansible-setup/ansible.cfg rename to automation/vm-ansible-setup/ansible.cfg diff --git a/automated/vm-ansible-setup/hosts b/automation/vm-ansible-setup/hosts similarity index 100% rename from automated/vm-ansible-setup/hosts rename to automation/vm-ansible-setup/hosts diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part1.yml b/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml similarity index 100% rename from automated/vm-ansible-setup/playbooks/setup_vm_part1.yml rename to automation/vm-ansible-setup/playbooks/setup_vm_part1.yml diff --git a/automated/vm-ansible-setup/playbooks/setup_vm_part2.yml b/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml similarity index 100% rename from automated/vm-ansible-setup/playbooks/setup_vm_part2.yml rename to automation/vm-ansible-setup/playbooks/setup_vm_part2.yml From 7760085c0ee00873b74d633c39974c88fdf42e62 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Fri, 14 Mar 2025 18:14:07 +0200 Subject: [PATCH 11/44] automation/README.md: added curl links for tf files and context to terraform.tfvars --- automation/README.md | 105 +++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/automation/README.md b/automation/README.md index 3236c27..fb10281 100644 --- a/automation/README.md +++ b/automation/README.md @@ -63,6 +63,8 @@ Use existing partial ## โœจ 1.6. Download `gcloud` locally +Link to `gcloud` CLI install docs at this [link here](https://cloud.google.com/sdk/docs/install). +
๐ŸชŸ Windows @@ -89,7 +91,7 @@ Use existing partial from DS setup Use existing partial from DS setup
-Cut Service account key here. +Remove section on creating a service account. Or leave it in but don't create a key for it. ## 1.7. Authorize local `gcloud` @@ -102,7 +104,7 @@ Add something about Windows for the installer ## 1.8. Visual Studio Code -Use existing partial +Use existing partial. Modify for **Remote - SSH** connection. ## โœจ 1.9. Install Terraform Locally @@ -140,7 +142,20 @@ sudo apt update && sudo apt install terraform ## โœจ 1.10. Create your VM with Terraform -Download files. This will be a `curl` from the repo. +Will require different instructions for Windows, MacOS, and Linux. + +Download the `terraform` files needed to provision your VM. This will be a `curl` from the repo. + +```bash +# MacOS & Linux. TODO: add Windows +# TODO: Change branch name if before merging +mkdir -p ~/wagon-de-bootcamp +curl -L -o ~/wagon-de-bootcamp/main.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o ~/wagon-de-bootcamp/provider.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o ~/wagon-de-bootcamp/variables.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o ~/wagon-de-bootcamp/terraform.tfvars https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` For testing, copy the terraform files from `infra/` in the repo into `~/code//de-vm-setup`. Files to copy: - `main.tf` @@ -148,12 +163,12 @@ For testing, copy the terraform files from `infra/` in the repo into `~/code/ @@ -293,6 +315,8 @@ And run with: cd ~/vm-ansible-setup && ansible-playbook playbooks/setup_vm_part2.yml ``` +โ— If any errors occur, contact a teacher. You can safely run the playbook again. + Once the playbook has finished, we need to completely SHUT DOWN your VM from the GCP console at [this link here](https://console.cloud.google.com/compute/instances?). Closing your VS Code and opening it again is not sufficient. TODO: add image assets @@ -301,6 +325,38 @@ TODO: add image assets Things to check: +Python: + +```bash +python --version +# 3.12.8 +``` + +TODO: Add image assets from existing partial + +Pyenv: + +```bash +pyenv versions +# 3.12.8 +``` +TODO: Add image asset + +Pipx: + +```bash +pipx list +``` + +TODO: Add image asset + +Data Engineering Challenges repo remotes: + +```bash +cd ~/code//data-engineering-challenges +git remote -v +``` + Docker: ```bash docker run hello-world @@ -341,40 +397,11 @@ spark-shell TODO: Add image assets from existing partial -Pyenv: - -```bash -pyenv virtualenvs -# 3.12.8 -``` - -Python: - -```bash -python --version -# 3.12.8 -``` - -TODO: Add image assets from existing partial - -Pipx: - -```bash -pipx list -``` - -TODO: Add image asset - -Data Engineering Challenges repo remotes: - -```bash -cd ~/code//data-engineering-challenges -git remote -v -``` - ## 3.3. Run make install +To create python venvs. + ```bash export GITHUB_USERNAME=`gh api user | jq -r '.login'` echo $GITHUB_USERNAME From fa02be1abdee8e7900a37bf78f3efcb11a3f5944 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Fri, 14 Mar 2025 18:19:16 +0200 Subject: [PATCH 12/44] automation/README.md: added more context and TODO tags --- automation/README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/automation/README.md b/automation/README.md index fb10281..ec95e85 100644 --- a/automation/README.md +++ b/automation/README.md @@ -195,18 +195,27 @@ instance_user = "taylorswift" # the result of `whoami` Make sure to save the `terraform.tfvars` file and run: ```bash +# MacOS & Linux. TODO: add Windows +cd ~/wagon-de-bootcamp + terraform init terraform apply -auto-approve ``` +Your VM should now be up and running! Check the GCP Compute Engine Console at this [link here](console.cloud.google.com/compute/instances) to confirm. + ## โœจ 1.11. Connect to your VM +In a terminal enter the following command: + ```bash gcloud compute config-ssh ``` -And connect via VS Code +And connect via VS Code. + +TODO: Add image assets
@@ -282,7 +291,7 @@ TODO: Add image assets Use existing partial -Can't be easily automated without creating & copying SSH keys, and generating GitHub PAT tokens. +Can't be easily automated without creating and copying SSH keys, and generating GitHub PAT tokens. ## 2.5. Copy LW Dotfiles @@ -317,7 +326,7 @@ cd ~/vm-ansible-setup && ansible-playbook playbooks/setup_vm_part2.yml โ— If any errors occur, contact a teacher. You can safely run the playbook again. -Once the playbook has finished, we need to completely SHUT DOWN your VM from the GCP console at [this link here](https://console.cloud.google.com/compute/instances?). Closing your VS Code and opening it again is not sufficient. +Once the playbook has finished, you need to completely SHUT DOWN your VM from the GCP console at [this link here](https://console.cloud.google.com/compute/instances). Closing your VS Code and opening it again is not sufficient. TODO: add image assets @@ -340,6 +349,7 @@ Pyenv: pyenv versions # 3.12.8 ``` + TODO: Add image asset Pipx: @@ -357,6 +367,8 @@ cd ~/code//data-engineering-challenges git remote -v ``` +TODO: Add image asset + Docker: ```bash docker run hello-world @@ -400,6 +412,8 @@ TODO: Add image assets from existing partial ## 3.3. Run make install +Use existing partial + To create python venvs. ```bash From ec15e852af9caa580f3b7e0aa1af70b862e5f805 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 11:22:03 +0200 Subject: [PATCH 13/44] Updated main.tf to create and attach a static external IP address --- automation/infra/main.tf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/automation/infra/main.tf b/automation/infra/main.tf index 8d88935..15b9f0a 100644 --- a/automation/infra/main.tf +++ b/automation/infra/main.tf @@ -1,3 +1,9 @@ +resource "google_compute_address" "static_ip" { + name = "${var.instance_name}-static-ip" + region = var.region +} + + resource "google_compute_instance" "my-instance" { name = var.instance_name machine_type = "e2-standard-4" @@ -14,7 +20,8 @@ resource "google_compute_instance" "my-instance" { network_interface { network = "default" access_config { - # assigns an ephemeral external IP address + nat_ip = google_compute_address.static_ip.address + network_tier = "PREMIUM" } } From f51c763350d44ebac1be3918b260e6f34fac44e6 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 11:41:19 +0200 Subject: [PATCH 14/44] added outputs.tf for feedback on External IP address --- automation/infra/outputs.tf | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 automation/infra/outputs.tf diff --git a/automation/infra/outputs.tf b/automation/infra/outputs.tf new file mode 100644 index 0000000..7d8908a --- /dev/null +++ b/automation/infra/outputs.tf @@ -0,0 +1,9 @@ +output "static_ip" { + description = "Static Public IP of the VM" + value = google_compute_address.static_ip.address +} + +output "instance_ip" { + description = "External IP of the VM" + value = google_compute_instance.my-instance.network_interface[0].access_config[0].nat_ip +} From 0ce65c53ffc3713086b5bb5e135f6586cb0d3a7e Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 11:41:40 +0200 Subject: [PATCH 15/44] automation/README.md: added outputs for manual testing --- automation/README.md | 159 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 11 deletions(-) diff --git a/automation/README.md b/automation/README.md index ec95e85..f603ece 100644 --- a/automation/README.md +++ b/automation/README.md @@ -338,7 +338,11 @@ Python: ```bash python --version -# 3.12.8 +``` + +Should return: +```bash +Python 3.12.8 ``` TODO: Add image assets from existing partial @@ -347,10 +351,14 @@ Pyenv: ```bash pyenv versions -# 3.12.8 ``` -TODO: Add image asset +Should return: + +```bash + system +* 3.12.8 (set by /home//.pyenv/version) +``` Pipx: @@ -358,40 +366,142 @@ Pipx: pipx list ``` -TODO: Add image asset +Should return: + +```bash +venvs are in /home//.local/share/pipx/venvs +apps are exposed on your $PATH at /home//.local/bin +manual pages are exposed at /home//.local/share/man + package poetry 2.1.1, installed using Python 3.12.8 + - poetry + package ruff 0.11.0, installed using Python 3.12.8 + - ruff + package tldr 3.3.0, installed using Python 3.12.8 + - tldr + - man1/tldr.1 +``` Data Engineering Challenges repo remotes: ```bash -cd ~/code//data-engineering-challenges +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges git remote -v ``` -TODO: Add image asset +Should return: + +```bash +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` Docker: ```bash docker run hello-world ``` -โ— If you get a permission error, SHUT DOWN your VM from the GCP console and turn it on again. Closing VS Code and opening it again is insufficient. +Should return: + +```bash +Unable to find image 'hello-world:latest' locally +latest: Pulling from library/hello-world +e6590344b1a5: Pull complete +Digest: sha256:7e1a4e2d11e2ac7a8c3f768d4166c2defeb09d2a750b010412b6ea13de1efb19 +Status: Downloaded newer image for hello-world:latest + +Hello from Docker! +This message shows that your installation appears to be working correctly. + +To generate this message, Docker took the following steps: + 1. The Docker client contacted the Docker daemon. + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. + (amd64) + 3. The Docker daemon created a new container from that image which runs the + executable that produces the output you are currently reading. + 4. The Docker daemon streamed that output to the Docker client, which sent it + to your terminal. + +To try something more ambitious, you can run an Ubuntu container with: + $ docker run -it ubuntu bash + +Share images, automate workflows, and more with a free Docker ID: + https://hub.docker.com/ + +For more examples and ideas, visit: + https://docs.docker.com/get-started/ +``` TODO: Add image assets from existing partial -Minikube: +Kubernetes: + +We can start by testing `minikube`: ```bash # Start minikube start +``` + +Should return: +```bash +๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) +โœจ Automatically selected the docker driver. Other choices: none, ssh +๐Ÿ“Œ Using Docker driver with root privileges +๐Ÿ‘ Starting "minikube" primary control-plane node in "minikube" cluster +๐Ÿšœ Pulling base image v0.0.46 ... +๐Ÿ’พ Downloading Kubernetes v1.32.0 preload ... + > gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 88.19 M + > preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 32.20 M +๐Ÿ”ฅ Creating docker container (CPUs=2, Memory=3900MB) ... +๐Ÿณ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ... + โ–ช Generating certificates and keys ... + โ–ช Booting up control plane ... + โ–ช Configuring RBAC rules ... +๐Ÿ”— Configuring bridge CNI (Container Networking Interface) ... +๐Ÿ”Ž Verifying Kubernetes components... + โ–ช Using image gcr.io/k8s-minikube/storage-provisioner:v5 +๐ŸŒŸ Enabled addons: storage-provisioner, default-storageclass +๐Ÿ„ Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default +``` + +And then make sure the kubernetes CLI utility, `kubectl` works with: + +```bash # Get pods kubectl get po -A +``` + +Should return: +```bash +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s +kube-system etcd-minikube 1/1 Running 0 78s +kube-system kube-apiserver-minikube 1/1 Running 0 76s +kube-system kube-controller-manager-minikube 1/1 Running 0 76s +kube-system kube-proxy-stk77 1/1 Running 0 72s +kube-system kube-scheduler-minikube 1/1 Running 0 76s +kube-system storage-provisioner 1/1 Running 1 (41s ago) 75s +``` + +And because `minikube` is resource intensive, stop it for now with: + +```bash # Stop minikube delete --all ``` -TODO: Add image assets from existing partial +Should return: + +```bash +๐Ÿ”ฅ Deleting "minikube" in docker ... +๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... +๐Ÿ’€ Removed all traces of the "minikube" cluster. +๐Ÿ”ฅ Successfully deleted all profiles +``` Terraform: @@ -399,7 +509,12 @@ Terraform: terraform --version ``` -TODO: Add image assets from existing partial +Should return: + +```bash +Terraform v1.11.2 +on linux_amd64 +``` Spark: @@ -407,8 +522,30 @@ Spark: spark-shell ``` -TODO: Add image assets from existing partial +Should take you into the spark shell that looks like: + +```bash +Setting default log level to "WARN". +To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). +25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable +Spark context Web UI available at http://lw-de-vm.europe-north1-b.c.wagon-de.internal:4040 +Spark context available as 'sc' (master = local[*], app id = local-1742288096829). +Spark session available as 'spark'. +Welcome to + ____ __ + / __/__ ___ _____/ /__ + _\ \/ _ \/ _ `/ __/ '_/ + /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 + /_/ + +Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_442) +Type in expressions to have them evaluated. +Type :help for more information. + +scala> +``` +Type `:quit` and hit enter to exit the spark-shell and continue. ## 3.3. Run make install From 8db0dafcd7099e1f6c5073cdfc8c5f155f7fae4d Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 11:49:09 +0200 Subject: [PATCH 16/44] Removed redundant partials --- _partials/docker.md | 34 ----------------- _partials/gcp_setup_end.md | 52 ------------------------- _partials/gcp_setup_mid.md | 11 ------ _partials/gcp_setup_wsl.md | 67 --------------------------------- _partials/kata.md | 7 ---- _partials/nbextensions.md | 75 ------------------------------------- _partials/osx_python.md | 75 ------------------------------------- _partials/pip.md | 43 --------------------- _partials/python_checkup.md | 31 --------------- _partials/tldr.md | 36 ------------------ _partials/virtualenv.md | 24 ------------ _partials/win_docker.md | 23 ------------ _partials/win_jupyter.md | 42 --------------------- 13 files changed, 520 deletions(-) delete mode 100644 _partials/docker.md delete mode 100644 _partials/gcp_setup_end.md delete mode 100644 _partials/gcp_setup_mid.md delete mode 100644 _partials/gcp_setup_wsl.md delete mode 100644 _partials/kata.md delete mode 100644 _partials/nbextensions.md delete mode 100644 _partials/osx_python.md delete mode 100644 _partials/pip.md delete mode 100644 _partials/python_checkup.md delete mode 100644 _partials/tldr.md delete mode 100644 _partials/virtualenv.md delete mode 100644 _partials/win_docker.md delete mode 100644 _partials/win_jupyter.md diff --git a/_partials/docker.md b/_partials/docker.md deleted file mode 100644 index 6c78316..0000000 --- a/_partials/docker.md +++ /dev/null @@ -1,34 +0,0 @@ -## Docker ๐Ÿ‹ - -Docker is an open platform for developing, shipping, and running applications. - -_if you already have Docker installed on your machine please update with the latest version_ - -### Install Docker - -Go to [Docker](https://docs.docker.com/get-docker/) website and choose your operating system: - -![](images/docker.png) - -Then follow the setup instructions, you are going to install a desktop application. - -Once done and launched, check Docker is up and running: - -```bash -docker info -``` - -You should get: - -
- โ—๏ธ I received a permission denied when trying to connect to the Docker Daemon socket. - -If you receive an error similar to the one below, navigate to the (GCP Compute Engine Console)[https://console.cloud.google.com/compute/instances] and STOP your VM (closing VSCode is not enough). - -![](images/docker_permission_denied_socket.png) - -It will take a few minutes for your VM to turn off. Once it's fully off, turn your VM on again (check the box and click START) and try `docker run hello-world` again. If this doesn't work, raise a ticket with a teacher. - -
- -![](images/docker_info.png) diff --git a/_partials/gcp_setup_end.md b/_partials/gcp_setup_end.md deleted file mode 100644 index 90d3e12..0000000 --- a/_partials/gcp_setup_end.md +++ /dev/null @@ -1,52 +0,0 @@ - -
- โ„น๏ธ How to find the absolute path of a file? - You can drag and drop the file in your terminal. -
- -**Restart** your terminal and run: - -``` bash -echo $GOOGLE_APPLICATION_CREDENTIALS -``` - -The ouptut should be the following: - -```bash -/some/absolute/path/to/your/gcp/SERVICE_ACCOUNT_JSON_FILE_CONTAINING_YOUR_SECRET_KEY.json -``` - -Now let's verify that the path to your service account json file is correct: - -``` bash -cat $(echo $GOOGLE_APPLICATION_CREDENTIALS) -``` - -๐Ÿ‘‰ This command should display the content of your service account json file. If it does not, ask for a TA ๐Ÿ™ - -Your code and utilities are now able to access the resources of your GCP account. - -Let's proceed with the final steps of configuration... - -- List the service accounts associated to your active account and current project -```bash -gcloud iam service-accounts list -``` -- Retrieve the service account email address, e.g. `SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com` -- List the roles of the service account from the cli (replace PROJECT_ID and SERVICE_ACCOUNT_EMAIL) -```bash -gcloud projects get-iam-policy PROJECT_ID \ ---flatten="bindings[].members" \ ---format='table(bindings.role)' \ ---filter="bindings.members:SERVICE_ACCOUNT_EMAIL" -``` -- You should see that your service account has a role of `roles/owner` - -
- Troubleshooting - -- `AccessDeniedException: 403 The project to be billed is associated with an absent billing account.` - - Make sure that billing is enabled for your Google Cloud Platform project https://cloud.google.com/billing/docs/how-to/modify-project -
- -๐Ÿ You are done with the GCP setup! diff --git a/_partials/gcp_setup_mid.md b/_partials/gcp_setup_mid.md deleted file mode 100644 index 6bbe4ec..0000000 --- a/_partials/gcp_setup_mid.md +++ /dev/null @@ -1,11 +0,0 @@ -- Store the service account json file somewhere you'll remember, for example: - -``` bash -/Users/MACOS_USERNAME/code/GITHUB_NICKNAME/gcp/SERVICE_ACCOUNT_JSON_FILE_CONTAINING_YOUR_SECRET_KEY.json -``` - -- Store the **absolute path** to the `JSON` file as an environment variable: - -``` bash -echo 'export GOOGLE_APPLICATION_CREDENTIALS=/path/to/the/SERVICE_ACCOUNT_JSON_FILE_CONTAINING_YOUR_SECRET_KEY.json' >> ~/.aliases -``` diff --git a/_partials/gcp_setup_wsl.md b/_partials/gcp_setup_wsl.md deleted file mode 100644 index cfb48b2..0000000 --- a/_partials/gcp_setup_wsl.md +++ /dev/null @@ -1,67 +0,0 @@ -We will now move the service account json file from your Windows disk to the Ubuntu disk. This will allow the development tools in Ubuntu to access to the ressources of your GCP account. - -First, let's create a directory in which we will store the file. - -๐Ÿ‘‰ Open an Ubuntu terminal and run the following commands - -๐Ÿšจ replace `GITHUB_NICKNAME` by your **GitHub** nickname - -``` bash -cd ~/code/GITHUB_NICKNAME -ls -la -``` - -If the command does not show the `dotfiles` directory, ask for a TA ๐Ÿ™ - -Otherwise, you can proceed with the setup: - -``` bash -mkdir gcp -``` - -![](images/wsl-gcp-dir.png) - -We will now move the service account json file to the `gcp` directory we just created. - -Open a Windows **File Explorer** (Win + E) and locate the `gcp` directory in the Ubuntu file system. - -You can either: -- Use the **Quick access** link that we created earlier -- manually type the location of the `gcp` directory in the Ubuntu file system in the address bar: - -``` -\\wsl$\Ubuntu\home\UBUNTU_USERNAME\code\GITHUB_NICKNAME -``` - - -๐Ÿšจ if you opt for the second option: -- replace `UBUNTU_USERNAME` by the username that you choose during the **Ubuntu** setup -- replace `GITHUB_NICKNAME` by your **GitHub** nickname - -![](images/wsl-gcp-key.png) - -Once you have located the `gcp` directory in the Windows **File Explorer**, move the service account json file that you downloaded inside of it. - -The file should now be visible from Ubuntu file system. - -๐Ÿ‘‰ Open an Ubuntu terminal and verify that the service account json file has been moved - -``` bash -cd gcp -ls -la -``` - -![](images/wsl-gcp-dir-2.png) - -If you do not see the service account json file listed in the `gcp` directory, ask for a TA ๐Ÿ™ - -We will now store the path to your service account json file in an environment variable. - -๐Ÿšจ in the following command, replace: -- `UBUNTU_USERNAME` by the username that you choose during the **Ubuntu** setup -- `GITHUB_NICKNAME` by your **GitHub** nickname -- `SERVICE_ACCOUNT_JSON_FILE_CONTAINING_YOUR_SECRET_KEY.json` by the name of your service account json file - -``` bash -echo 'export GOOGLE_APPLICATION_CREDENTIALS=/home/UBUNTU_USERNAME/code/GITHUB_NICKNAME/gcp/SERVICE_ACCOUNT_JSON_FILE_CONTAINING_YOUR_SECRET_KEY.json' >> ~/.aliases -``` diff --git a/_partials/kata.md b/_partials/kata.md deleted file mode 100644 index 4c26cbf..0000000 --- a/_partials/kata.md +++ /dev/null @@ -1,7 +0,0 @@ -## (Bonus) Kata - -If you are done with your setup, please ask around if some classmates need some help with theirs (macOS, Linux, Windows). We will have our first lectures at 2pm and will talk about the Setup you just did + onboard you on Kitt. - -If you don't have a lot of experience with `git` and GitHub, please [(re-)watch this workshop](https://www.youtube.com/watch?v=Z9fIBT2NBGY) (`1.25` playback speed is fine). - -If you do, then you can wait for the first lecture working on this [Tic-Tac-Toe Kata](https://www.codewars.com/kata/5b817c2a0ce070ace8002be0/train/python) diff --git a/_partials/nbextensions.md b/_partials/nbextensions.md deleted file mode 100644 index 5d0a698..0000000 --- a/_partials/nbextensions.md +++ /dev/null @@ -1,75 +0,0 @@ -## `jupyter` notebook extensions - -Pimp your `jupyter` notebooks with awesome extensions: - -```bash -# install nbextensions -jupyter contrib nbextension install --user -jupyter nbextension enable toc2/main -jupyter nbextension enable collapsible_headings/main -jupyter nbextension enable spellchecker/main -jupyter nbextension enable code_prettify/code_prettify -``` - -### Custom CSS - -Improve the display of the [`details` disclosure elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) in your notebooks. - -Open `custom/custom.css` in the config directory: -```bash -cd $(jupyter --config-dir) -mkdir -p custom -touch custom/custom.css - custom/custom.css -``` -Edit `custom.css` with: - -```css -summary { - cursor: pointer; - display:list-item; -} -summary::marker { - font-size: 1em; -} -``` - -You can close . - -### `jupyter` check up - -Let's reset your terminal: - -```bash -exec zsh -``` - -Now, check you can launch a notebook server on your machine: - -```bash -jupyter notebook -``` - -Your web browser should open on a `jupyter` window: - -![jupyter.png](images/jupyter.png) - -Click on `New`: - -![jupyter_new.png](images/jupyter_new.png) - -A tab should open on a new notebook: - -![jupyter_notebook.png](images/jupyter_notebook.png) - -### `nbextensions` check up - -Perform a sanity check for `jupyter notebooks nbextensions`. Click on `Nbextensions`: - -![jupyter_nbextensions.png](images/jupyter_nbextensions.png) - -Untick _"disable configuration for nbextensions without explicit compatibility"_ then check that _at least_ all `nbextensions` circled in red are enabled: - -![nbextensions.png](images/nbextensions.png) - -You can close your web browser then terminate the jupyter server with `CTRL` + `C`. diff --git a/_partials/osx_python.md b/_partials/osx_python.md deleted file mode 100644 index b659a56..0000000 --- a/_partials/osx_python.md +++ /dev/null @@ -1,75 +0,0 @@ -## Installing Python (with [`pyenv`](https://github.com/pyenv/pyenv)) - -Before installing Python, please check your `xz` version with: - -```bash -brew info xz -``` - -It should be more than `5.2.0`, **if not** you should run: - -```bash -sudo rm -rf /usr/local/opt/xz -brew upgrade -brew install xz -``` - -Then run: - -```bash -brew install readline -``` - -macOS comes with an outdated version of Python that we don't want to use. You might already have installed Anaconda or something else to tinker with Python and Data Science packages. All of this does not really matter as we are going to do a professional setup of Python where you'll be able to switch which version you want to use whenever you type `python` in the terminal. - -First let's install `pyenv` with the following Terminal command: - -```bash -brew install pyenv -exec zsh -``` - -Let's install the [latest stable version of Python](https://www.python.org/doc/versions/) supported by Le Wagon's curriculum: - -```bash -pyenv install -``` - -This command might take a while, this is perfectly normal. Don't hesitate to help other students seated next to you! - -
- ๐Ÿ›  Troubleshooting - -If you encounter an error installing Python with `pyenv` about `zlib`: - -```txt -zipimport.ZipImportError: can't decompress data; zlib not available -``` - -Install `zlib` with: - -```bash -brew install zlib -export LDFLAGS="-L/usr/local/opt/zlib/lib" -export CPPFLAGS="-I/usr/local/opt/zlib/include" -``` - -Then try to install Python again: - -```bash -pyenv install -``` - -It could raise another error about `bzip2`, you can ignore it and continue to the next step. - -
-
- -OK once this command is complete, we are going to tell the system to use this version of Python **by default**. This is done with: - -```bash -pyenv global -exec zsh -``` - -To check if this worked, run `python --version`. If you see ``, perfect! If not, ask a TA that will help you debug the problem thanks to `pyenv versions` and `type -a python` (`python` should be using the `.pyenv/shims` version first). diff --git a/_partials/pip.md b/_partials/pip.md deleted file mode 100644 index 4392db5..0000000 --- a/_partials/pip.md +++ /dev/null @@ -1,43 +0,0 @@ -## Python packages - -Now that we have a pristine `lewagon` virtual environment, it's time to install some packages in it. - -First, let's upgrade `pip`, the tool to install Python Packages from [pypi.org](https://pypi.org). In the latest terminal where the virtualenv `lewagon` is activated, run: - -```bash -pip install --upgrade pip -``` - -Then let's install some packages for the first weeks of the program: - -$MAC_START -If your computer uses **Apple Silicon**, expand the paragraph below and go through it. Otherwise ignore it. - -
- ๐Ÿ‘‰  Setup for Apple Silicon ๐Ÿ‘ˆ - -``` bash -pip install -r https://raw.githubusercontent.com/lewagon/data-setup/master/specs/releases/apple_silicon.txt -``` -
- -If your computer uses **Apple Intel**, expand the paragraph below and go through it. Otherwise ignore it. - -
- ๐Ÿ‘‰  Setup for Apple Intel ๐Ÿ‘ˆ - -``` bash -pip install -r https://raw.githubusercontent.com/lewagon/data-setup/master/specs/releases/apple_intel.txt -``` -
-$MAC_END -$WINDOWS_START -``` bash -pip install -r https://raw.githubusercontent.com/lewagon/data-setup/master/specs/releases/linux.txt -``` -$WINDOWS_END -$LINUX_START -``` bash -pip install -r https://raw.githubusercontent.com/lewagon/data-setup/master/specs/releases/linux.txt -``` -$LINUX_END diff --git a/_partials/python_checkup.md b/_partials/python_checkup.md deleted file mode 100644 index 363c219..0000000 --- a/_partials/python_checkup.md +++ /dev/null @@ -1,31 +0,0 @@ -### Python setup check up - -Check your Python version with the following commands: -```bash -zsh -c "$(curl -fsSL )" -``` - -Run the following command to check if you successfully installed the required packages: -```bash -zsh -c "$(curl -fsSL )" -``` - -Now run the following command to check if you can load these packages: -```bash -python -c "$(curl -fsSL )" -``` - -Make sure you can run Jupyter: - -```bash -jupyter notebook -``` - -And open a `Python 3` notebook. - -Make sure that you are running the correct python version in the notebook. Open a cell and run : -``` python -import sys; sys.version -``` - -Here you have it! A complete python virtual env with all the third-party packages you'll need for the whole bootcamp. diff --git a/_partials/tldr.md b/_partials/tldr.md deleted file mode 100644 index 548b10f..0000000 --- a/_partials/tldr.md +++ /dev/null @@ -1,36 +0,0 @@ -## TLDR - -Add TLDR - a modern addition to MAN pages, which will help you find nice documentation and examples on most Linux commands: - -```bash -cd ~ -pip3 install -U pip -pip3 install tldr -``` -โ—๏ธ It is one of the very few tools we will install from the default system python interpreter, because it has se few [dependencies](https://github.com/tldr-pages/tldr/blob/main/requirements.txt) - -You can try `tldr` with: - -```bash -tldr gh -``` - -โ„น๏ธ It's normal that it takes ~1 minute the first time, as the cache needs to be built. Subsequent calls will be fast. - -Finally you should get: - -tldr - -## gRPCurl - -gRPCurl is `curl` for [gRPC servers](https://grpc.io/docs/what-is-grpc/introduction/). - -- Install `grpcurl` - ```bash - curl -s https://grpc.io/get_grpcurl | bash - ``` -- Add `grpcurl` to your `PATH` - ```bash - echo '# Add grpcurl to PATH' >> ~/.zshrc - echo 'PATH=$PATH:$HOME/.grpcurl/bin/' >> ~/.zshrc - ``` diff --git a/_partials/virtualenv.md b/_partials/virtualenv.md deleted file mode 100644 index 341f545..0000000 --- a/_partials/virtualenv.md +++ /dev/null @@ -1,24 +0,0 @@ -## Python Virtual Environment - -Before we start installing relevant Python packages, we will isolate the setup for the Bootcamp into a **dedicated** virtual environment. We will use a `pyenv` plugin called [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv). - -First let's install this plugin: - -```bash -git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv -exec zsh -``` - -Let's create the virtual environment we are going to use during the whole bootcamp: - -```bash -pyenv virtualenv lewagon -``` - -Let's now set the virtual environment with: - -```bash -pyenv global lewagon -``` - -Great! Anytime we'll install Python package, we'll do it in that environment. diff --git a/_partials/win_docker.md b/_partials/win_docker.md deleted file mode 100644 index f8f44cf..0000000 --- a/_partials/win_docker.md +++ /dev/null @@ -1,23 +0,0 @@ -## Docker ๐Ÿ‹ - -Docker is an open platform for developing, shipping, and running applications. - -_if you already have Docker installed on your machine please update with the latest version_ - -### Install Docker - -Go to [Docker for WSL2](https://docs.docker.com/docker-for-windows/wsl/). - -Download and install the Docker Desktop WSL 2 backend. - -Once done, start Docker. - -You should be able to run in a Ubuntu terminal: - -```bash -docker run hello-world -``` - -The following message should print: - -![](images/docker_hello.png) diff --git a/_partials/win_jupyter.md b/_partials/win_jupyter.md deleted file mode 100644 index 1a725e4..0000000 --- a/_partials/win_jupyter.md +++ /dev/null @@ -1,42 +0,0 @@ - -## Configuring Jupyter Notebook to open in your browser - -Let's generate the configuration file for **Jupyter Notebook**... - -``` bash -jupyter notebook --generate-config -``` - -โš ๏ธ Please copy the path returned by the previous command. - -We will now edit the generated Jupyter configuration file: - -``` bash - $HOME/.jupyter/jupyter_notebook_config.py -``` - -Locate the following line in the configuration file: - -``` python -# c.NotebookApp.use_redirect_file = True -``` - -And replace it with this one: - -``` python -c.NotebookApp.use_redirect_file = False -``` - -Let's try to run Jupyter: - -``` bash -jupyter notebook -``` - -This command should have opened a Jupyter page in your browser: - -![](images/wsl_jupyter_notebook.png) - -If it is not the case, please call a TA. - -To stop the Jupyter server in the terminal, press `Ctrl` + `C`, enter y, then press Enter. From 1237bea15198a1f5b46e1c3ab23a5c30d75f0a31 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 16:56:57 +0200 Subject: [PATCH 17/44] ansible: setup_vm_part2.yml, added note to python 3.12.8 install --- automation/vm-ansible-setup/playbooks/setup_vm_part2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml b/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml index fd3fe25..ab7aadd 100644 --- a/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml +++ b/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml @@ -172,7 +172,7 @@ changed_when: false tags: python - - name: Install Python 3.12.8 with pyenv + - name: Install Python 3.12.8 with pyenv - takes a while command: > zsh -c 'export PYENV_ROOT="$HOME/.pyenv"; export PATH="$PYENV_ROOT/bin:$PATH"; From f78151d152908244cd8b6720a86ea06abb172ff6 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 16:57:37 +0200 Subject: [PATCH 18/44] updated partials --- _partials/gcp_adc_auth.md | 13 ++ _partials/gcp_cli_oauth.md | 36 +++++ _partials/gcp_cli_setup.md | 37 ++++- _partials/intro.md | 36 +++++ _partials/terraform.md | 19 ++- _partials/terraform_vm.md | 111 ++++++++++++++ _partials/ubuntu_ansible_part1.md | 67 +++++++++ _partials/ubuntu_ansible_part2.md | 85 +++++++++++ _partials/ubuntu_gcloud.md | 4 +- _partials/ubuntu_terraform.md | 41 +++++ _partials/ubuntu_vm_test.md | 234 +++++++++++++++++++++++++++++ _partials/vscode_remote_ssh.md | 62 -------- _partials/vscode_ssh_connection.md | 43 ++++++ 13 files changed, 719 insertions(+), 69 deletions(-) create mode 100644 _partials/gcp_adc_auth.md create mode 100644 _partials/gcp_cli_oauth.md create mode 100644 _partials/terraform_vm.md create mode 100644 _partials/ubuntu_ansible_part1.md create mode 100644 _partials/ubuntu_ansible_part2.md create mode 100644 _partials/ubuntu_terraform.md create mode 100644 _partials/ubuntu_vm_test.md create mode 100644 _partials/vscode_ssh_connection.md diff --git a/_partials/gcp_adc_auth.md b/_partials/gcp_adc_auth.md new file mode 100644 index 0000000..ca632aa --- /dev/null +++ b/_partials/gcp_adc_auth.md @@ -0,0 +1,13 @@ +## Google Authentication + +Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. + +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your Application Default Credentials, in your terminal run: + +```bash +gcloud auth application-default login +``` diff --git a/_partials/gcp_cli_oauth.md b/_partials/gcp_cli_oauth.md new file mode 100644 index 0000000..5cb0b2d --- /dev/null +++ b/_partials/gcp_cli_oauth.md @@ -0,0 +1,36 @@ +### Authenticate gcloud + +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. + +To authenticate `gcloud`, run: + +```bash +gcloud auth login +``` + +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V + +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. + +To set your project, replace `` with your GCP Project ID and run: + +```bash +gcloud config set project +``` + +To confirm your setup, run: + +```bash +gcloud config list +``` + +You should get an output similar to: + +```bash +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] +``` diff --git a/_partials/gcp_cli_setup.md b/_partials/gcp_cli_setup.md index 9329452..e1e7c37 100644 --- a/_partials/gcp_cli_setup.md +++ b/_partials/gcp_cli_setup.md @@ -1,7 +1,11 @@ +## Google Cloud CLI -## `gcloud` CLI +The `gcloud` Command Line Interface (CLI) is used to communicate with Google Cloud Platform services through your terminal. -Before Setting up our Google Cloud Platform account let's configure the `gcloud` CLI (A command line interface for Google Cloud Platform). Run the below and follow the terminal prompts to update your $PATH and enable shell command completion for the `.zshrc` file: +### Install gcloud + +$MAC_START +Install with `brew`: ```bash brew install --cask google-cloud-sdk @@ -12,3 +16,32 @@ Then you can: ```bash $(brew --prefix)/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/install.sh ``` + +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#) +$MAC_END +$WINDOWS_START + +To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). + +Once it's finished downloading, launch the installer as administrator and follow the prompts. + +$WINDOWS_END +$LINUX_START +Add the `APT` repository and install with: + +```bash +echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +sudo apt-get install apt-transport-https ca-certificates gnupg +curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - +sudo apt-get update && sudo apt-get install google-cloud-sdk +sudo apt-get install google-cloud-sdk-app-engine-python +``` + +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) +$LINUX_END + +To test your install, run the following in your terminal: + +```bash +gcloud --version +``` diff --git a/_partials/intro.md b/_partials/intro.md index 87a0ec9..560b29a 100644 --- a/_partials/intro.md +++ b/_partials/intro.md @@ -6,4 +6,40 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: +This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! +- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! + +## Part 1: Setup your local computer + +In this section you'll setup your local computer and create some accounts. It will include things like: +1. Install some communication tools: Zoom, Slack +2. Create some accounts: Github, Google Cloud Platform (GCP) +3. Install Visual Studio Code (VS Code) +4. Install and authentication the GCP command line tool: `gcloud`. +5. Install **terraform** on your local computer. +6. Create your virtual machine with **terraform** and connect to it with **VS Code**! + +## Part 2: Configure your Virtual Machine Part 1 + +All parts of this section happen on your virtual machine. + +This section includes: +1. Authenticate your virtual machine with `gcloud` +2. Download and run an **ansible** playbook to partially configure your virtual machine. +3. Login to the Github command line tool on your virtual machine +4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! + +## Part 3: Configure your Virtual Machine Part 2 + +All parts of this section happen on your virtual machine. + +In this section you will: +1. Download and run a second **ansible** playbook for some more fine tuning. +2. Test your set up to make sure that everything has installed correctly. +3. Create some python environments. + + +Don't worry, we'll go into more detail in each of the individual sections. + Let's start :rocket: diff --git a/_partials/terraform.md b/_partials/terraform.md index b9c925f..887fce2 100644 --- a/_partials/terraform.md +++ b/_partials/terraform.md @@ -1,15 +1,27 @@ ## Terraform -Terraform is a tool for infrastructure as code (IAC) to define resources to create in the cloud! +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! -### Install terraform +$MAC_START +You can use `brew` to install terraform. In your terminal, run: +```bash +brew tap hashicorp/tap +brew install hashicorp/tap/terraform +``` +$MAC_END +$WINDOWS_START +To install terraform, download the binary from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). + +TODO: Unsure if anything needs to be added to PATH to get it to work +$WINDOWS_END +$LINUX_START Install some basic requirements ```bash sudo apt-get update && sudo apt-get install -y gnupg software-properties-common ``` -Terraform is not avaliable to apt by default so we need to make it avaliable! +Terraform is not available to apt by default so we need to make it available! ```bash wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ @@ -33,6 +45,7 @@ Now we can install terraform directly with apt ๐Ÿ‘‡ sudo apt update sudo apt-get install terraform ``` +$LINUX_END Verify the installation with: diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md new file mode 100644 index 0000000..079e1f2 --- /dev/null +++ b/_partials/terraform_vm.md @@ -0,0 +1,111 @@ +## Provisioning your Virtual Machine with Terraform + +We're almost at the point of creating your Virtual Machine. + +The specifications of the machine you'll use for the bootcamp are: +- Operation System: Ubuntu 22.04 LTS +- CPU: 4 Virtual CPU cores +- RAM: 16 GB +- Storage: 100 GB +- Network: Static External IP address + +### Cost ๐Ÿ’ธ + +Creating and running a Virtual Machine on Google Cloud Platform costs money. + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). + +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! + +You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. + +### Download terraform files + +We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. + +First we'll create a folder and download the terraform files with: + +$MAC_START +```bash +mkdir -p ~/wagon-de-bootcamp +curl -L -o ~/wagon-de-bootcamp/main.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o ~/wagon-de-bootcamp/provider.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o ~/wagon-de-bootcamp/variables.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o ~/wagon-de-bootcamp/terraform.tfvars https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` +$MAC_END +$WINDOWS_START +Using the Command Prompt (cmd), run the following: + +TODO: Requires testing + +```cmd +mkdir %USERPROFILE%\wagon-de-bootcamp +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\main.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\provider.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\variables.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\terraform.tfvars" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\.terraform.lock.hcl" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` +$WINDOWS_END +$LINUX_START +```bash +mkdir -p ~/code/wagon-de-bootcamp +curl -L -o ~/wagon-de-bootcamp/main.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o ~/wagon-de-bootcamp/provider.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o ~/wagon-de-bootcamp/variables.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o ~/wagon-de-bootcamp/terraform.tfvars https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` +$LINUX_END + + +### Set variables + +Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: + +```bash +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" +``` + +We'll need to change some values in this file. Here's were you can find the required values: +- **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). +- **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. +- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **instance_user:** in your terminal, run `whoami` and hit enter. + +After completing this file, it should look similar to: + +```bash +project_id = "wagon-bootcamp" +region = "europe-west1" +zone = "europe-west1-b" +instance_name = "lw-de-vm-tswift" +instance_user = "taylorswift" # result of `whoami` +``` + +Make sure to save the `terraform.tfvars` file and then run: + +```bash +cd ~/wagon-de-bootcamp + +terraform init + +terraform plan +``` + +And check the output, if you have any errors, raise a ticket with a teacher. + +If everything was successful, create your VM with: + +```bash +terraform apply -auto-approve +``` + +And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. diff --git a/_partials/ubuntu_ansible_part1.md b/_partials/ubuntu_ansible_part1.md new file mode 100644 index 0000000..27baa11 --- /dev/null +++ b/_partials/ubuntu_ansible_part1.md @@ -0,0 +1,67 @@ +## VM configuration with Ansible + +We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. + +Let's start by confirming that ansible is installed. In your terminal run: + +```bash +ansible --version +``` + +You should get an output similar to (some version numbers might change, that's fine): + +```bash +ansible [core 2.17.9] + config file = /etc/ansible/ansible.cfg + configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /usr/lib/python3/dist-packages/ansible + ansible collection location = /home/tswift/.ansible/collections:/usr/share/ansible/collections + executable location = /usr/bin/ansible + python version = 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3) + jinja version = 3.1.2 + libyaml = True +``` + +If not, raise a ticket with a teacher. + +### Ansible Playbook 1 + +If everything looks ok, lets create a folder and download the ansible files: + +```bash +mkdir -p ~/vm-ansible-setup/playbooks + +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml +``` + +And run with: + +```bash +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part1.yml +``` + +And the playbook should start running! + +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. + +### What is the playbook installing? + +This playbook is installing a few things, while the playbook is running, let's go through them: +- Updating system packages. Ubuntu uses the `APT` package manager. +- Changing the default shell from **bash** to **zsh**, a more customizable shell that is extensible and looks great! +- Installing the **Oh-My-ZSH** plugin for the **zsh** shell. We'll use it a bit later to add some quality of life plugins and extensions for `zsh`. +- Installing **Docker** on your Virtual Machine. Docker is an open platform for developing, shipping, and running applications. You will use it throughout the bootcamp +- Installing some **Kubernetes (k8s)** tooling: Kubernetes is a system designed to for auto-scaling containerized applications. + - Installing **kubectl**: `kubectl` is the CLI tool for interacting with kubernetes clusters. + - Installing **minikube**: Minikube is a way to quickly spin up a local kubernetes cluster. Great for developing! +- Installing **terraform**: we've already installed it once, but we need to install it on our VM! **Terraform** is an Infrastructure as Code (IaC) tool. +- Install the **GitHub CLI**: the CLI tool that we'll use to interact with your GitHub account directly from the terminal. + +The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. + +Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: + +![](/images/vscode_after_ansible1.png) diff --git a/_partials/ubuntu_ansible_part2.md b/_partials/ubuntu_ansible_part2.md new file mode 100644 index 0000000..2541398 --- /dev/null +++ b/_partials/ubuntu_ansible_part2.md @@ -0,0 +1,85 @@ +## VM configuration with Ansible - Part 2 + +### Ansible Playbook 2 + +We'll be using a second **ansible** playbook to further configure your Virtual Machine. + +Start by downloading the ansible playbook: + +```bash +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml +``` + +And run with: + +```bash +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part2.yml +``` + +And the playbook should start running! + +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. + +### What is the playbook installing? + +This playbook is installing and configuring a things, while the playbook is running, let's go through them: + +**Python and Poetry** + +Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python [3.12.8](https://www.python.org/downloads/release/python-3128/) + +- Install **pyenv** and **pyenv-virtualenv**. We'll use **pyenv** to manage the Python versions installed on the VM +- Install Python 3.12.8 with pyenv +- Install **pipx**: [Pipx](https://pipx.pypa.io/stable/) is used to install python packages we want _globally_ available while still using virtual environments, like Poetry! +- Installing a few global python packages with **pipx**: + - **Poetry:** [Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. + - **Ruff:** [Ruff](https://docs.astral.sh/ruff/) Is used to format and lint Python code. + - **tldr:** [tldr](https://github.com/tldr-pages/tldr) has much more readable version of `man` pages. Useful for quickly finding out how a program works. + +**VS Code Configuration** + +- Installing some **VS Code** extensions, but only on your VM. Here's a list of the extensions that are being installed: + - [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) + - [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) + - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + - [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) + - [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) + - [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) + - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + - [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +- Update the VS Code Python Interpreter path. + +**Shell and System Configuration** + +- Create the **direnv** poetry function. The same one from the lecture! This makes it easier to work with poetry. +- Adding some **Oh-My-ZSH** Plugins: by modifying your `.zshrc` file. Here's a list of the extra plugins: + - **pyenv**: Auto-complete for pyenv, a tool used to manage python virtual environments + - **gcloud**: Auto-complete for the gcloud CLI tool + - **ssh-agent**: Saves your SSH password so you only have to enter it once per session. + - **direnv**: A tool to load `.envrc` files when you `cd` into a directory. Great for loading environment variables. +- Installing **Spark**: Spark is a distributed data processing framework + +**Data Engineering Challenges Repository** + +The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. + +Here is an image of how the Repository setup works: + +![](/images/repo_overview.png) + +This allows you to work on challenges, but if we push any changes to the content, you can still access them! + +### Restart Virtual Machine + +Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). + +To shutdown your VM, navigate to the GCP Compute Engine Instances [console page ๐Ÿ”—](https://console.cloud.google.com/compute/instances). + +Select your VM instance and click on the stop button: + +![](/images/gcp_vm_stop.png) + +Wait for a few minutes until the VM shows that it is completely off. You may need to refresh the page, the GCP Console doesn't dynamically update. + +When the VM is completely off, turn it on again by selecting the check box next to your instance and clicking **START/RESUME**. Give it a minute to spin up, then connect via VS Code. diff --git a/_partials/ubuntu_gcloud.md b/_partials/ubuntu_gcloud.md index 0ce1342..32d97ca 100644 --- a/_partials/ubuntu_gcloud.md +++ b/_partials/ubuntu_gcloud.md @@ -10,7 +10,7 @@ sudo apt-get install google-cloud-sdk-app-engine-python ``` ๐Ÿ‘‰ [Install documentation](https://cloud.google.com/sdk/docs/install#deb) -### Create a service account key ๐Ÿ”‘ + diff --git a/_partials/ubuntu_terraform.md b/_partials/ubuntu_terraform.md new file mode 100644 index 0000000..0cbf9e7 --- /dev/null +++ b/_partials/ubuntu_terraform.md @@ -0,0 +1,41 @@ +## Terraform + +Terraform is a tool for infrastructure as code (IAC) to define resources to create in the cloud! + +### Install terraform + +Install some basic requirements +```bash +sudo apt-get update && sudo apt-get install -y gnupg software-properties-common +``` + +Terraform is not available to apt by default so we need to make it available! +```bash +wget -O- https://apt.releases.hashicorp.com/gpg | \ + gpg --dearmor | \ + sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null +``` + +```bash +gpg --no-default-keyring \ + --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ + --fingerprint +``` + +```bash +echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ + https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ + sudo tee /etc/apt/sources.list.d/hashicorp.list +``` + +Now we can install terraform directly with apt ๐Ÿ‘‡ +```bash +sudo apt update +sudo apt-get install terraform +``` + +Verify the installation with: + +```bash +terraform --version +``` diff --git a/_partials/ubuntu_vm_test.md b/_partials/ubuntu_vm_test.md new file mode 100644 index 0000000..716dd49 --- /dev/null +++ b/_partials/ubuntu_vm_test.md @@ -0,0 +1,234 @@ +## Check your Virtual Machine Setup + +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. + +โ— If any of these checks error out, raise a ticket with a teacher. + +#### Python + +To test: + +```bash +python --version +``` + +Should return: + +```bash +Python 3.12.8 +``` + +#### Pyenv + +To test: + +```bash +pyenv versions +``` + +Should return: + +```bash + system +* 3.12.8 (set by /home//.pyenv/version) +``` + +Note: There should be an `*` next to 3.12.8 + +#### Pipx + +To test: + +```bash +pipx list +``` + +Should return something similar too: + +```bash +venvs are in /home//.local/share/pipx/venvs +apps are exposed on your $PATH at /home//.local/bin +manual pages are exposed at /home//.local/share/man + package poetry 2.1.1, installed using Python 3.12.8 + - poetry + package ruff 0.11.0, installed using Python 3.12.8 + - ruff + package tldr 3.3.0, installed using Python 3.12.8 + - tldr + - man1/tldr.1 +``` + +#### Data Engineering Challenges repo remotes + +To test: + +```bash +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v +``` + +Should return: + +```bash +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` + +#### Docker + +To test: + +```bash +docker run hello-world +``` + +Should return: + +```bash +Unable to find image 'hello-world:latest' locally +latest: Pulling from library/hello-world +e6590344b1a5: Pull complete +Digest: sha256:7e1a4e2d11e2ac7a8c3f768d4166c2defeb09d2a750b010412b6ea13de1efb19 +Status: Downloaded newer image for hello-world:latest + +Hello from Docker! +This message shows that your installation appears to be working correctly. + +To generate this message, Docker took the following steps: + 1. The Docker client contacted the Docker daemon. + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. + (amd64) + 3. The Docker daemon created a new container from that image which runs the + executable that produces the output you are currently reading. + 4. The Docker daemon streamed that output to the Docker client, which sent it + to your terminal. + +To try something more ambitious, you can run an Ubuntu container with: + $ docker run -it ubuntu bash + +Share images, automate workflows, and more with a free Docker ID: + https://hub.docker.com/ + +For more examples and ideas, visit: + https://docs.docker.com/get-started/ +``` + +#### Kubernetes + +We can start by testing `minikube`: + +```bash +# Start +minikube start +``` + +Should return: + +```bash +๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) +โœจ Automatically selected the docker driver. Other choices: none, ssh +๐Ÿ“Œ Using Docker driver with root privileges +๐Ÿ‘ Starting "minikube" primary control-plane node in "minikube" cluster +๐Ÿšœ Pulling base image v0.0.46 ... +๐Ÿ’พ Downloading Kubernetes v1.32.0 preload ... + > gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 88.19 M + > preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 32.20 M +๐Ÿ”ฅ Creating docker container (CPUs=2, Memory=3900MB) ... +๐Ÿณ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ... + โ–ช Generating certificates and keys ... + โ–ช Booting up control plane ... + โ–ช Configuring RBAC rules ... +๐Ÿ”— Configuring bridge CNI (Container Networking Interface) ... +๐Ÿ”Ž Verifying Kubernetes components... + โ–ช Using image gcr.io/k8s-minikube/storage-provisioner:v5 +๐ŸŒŸ Enabled addons: storage-provisioner, default-storageclass +๐Ÿ„ Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default +``` + +And then make sure the kubernetes CLI utility, `kubectl`, works with: + +```bash +# Get pods +kubectl get po -A +``` + +Should return something similar too: + +```bash +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s +kube-system etcd-minikube 1/1 Running 0 78s +kube-system kube-apiserver-minikube 1/1 Running 0 76s +kube-system kube-controller-manager-minikube 1/1 Running 0 76s +kube-system kube-proxy-stk77 1/1 Running 0 72s +kube-system kube-scheduler-minikube 1/1 Running 0 76s +kube-system storage-provisioner 1/1 Running 1 (41s ago) 75s +``` + +And because `minikube` is resource intensive, stop it for now with: + +```bash +# Stop +minikube delete --all +``` + +Should return: + +```bash +๐Ÿ”ฅ Deleting "minikube" in docker ... +๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... +๐Ÿ’€ Removed all traces of the "minikube" cluster. +๐Ÿ”ฅ Successfully deleted all profiles +``` + +#### Terraform + +To test: + +```bash +terraform --version +``` + +Should return: + +```bash +Terraform v1.11.2 +on linux_amd64 +``` + +#### Spark + +To test: + +```bash +spark-shell +``` + +Should take you into the spark shell that looks like: + +```bash +Setting default log level to "WARN". +To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). +25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable +Spark context Web UI available at http://lw-de-vm.europe-north1-b.c.wagon-de.internal:4040 +Spark context available as 'sc' (master = local[*], app id = local-1742288096829). +Spark session available as 'spark'. +Welcome to + ____ __ + / __/__ ___ _____/ /__ + _\ \/ _ \/ _ `/ __/ '_/ + /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 + /_/ + +Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_442) +Type in expressions to have them evaluated. +Type :help for more information. + +scala> +``` + +Type `:quit` and hit enter to exit the spark-shell and continue. + +That's everything for now! diff --git a/_partials/vscode_remote_ssh.md b/_partials/vscode_remote_ssh.md index 29e3eaa..301d89d 100644 --- a/_partials/vscode_remote_ssh.md +++ b/_partials/vscode_remote_ssh.md @@ -11,65 +11,3 @@ We need to connect VS Code to a virtual machine in the cloud so you will only wo VS Code extensions - Remote - Details That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. - -### Virtual Machine connection - -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` - -vscode-connect-to-host - -- Click on `Add a new host` -- Type `ssh -i @`, for instance, my username is `somedude`, my private SSH key is located at `~/.ssh/id_rsa` on my local computer, my VM has a public IP of `34.77.50.76`: I'll type `ssh -i ~/.ssh/id_rsa somedude@34.77.50.76` - -vscode-ssh-connection-command - - -- When prompted to `Select SSH configuration file to update`, pick the one in your home directory, under the `.ssh` folder, `~/.ssh/config` basically. Usually VS Code will pick automatically the best option, so their default should work. - -vscode-add-host-ssh-config - -- You should get a pop-up on the bottom right notifying you the host has been added - -vscode-host-added - -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` > Pick your VM IP address - -vscode-add-new-host - -- The first time, VSCode might ask you for a security permission like below, say yes / continue. - -vscode-remote-connection-confirm - -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Terminal: Create New Terminal (in active workspace)` > You now have a Bash terminal in your virtual machine! - -vscode-command-palette-new-terminal -
-vscode-terminal - -- Still on your *local* computer, lets create a more readable version of your machine to connect to! - -```bash -code ~/.ssh/config -``` - -You should see something like the following: - -```bash -Host - HostName - IdentityFile - User -``` -You can now change Host to whatever you would like to see as the name of your connection or in terminal with `ssh `! - -โ—๏ธ It is important that the `Host` alias does not contain any whitespaces โ—๏ธ - -```bash -# For instance -Host "de-bootcamp-vm" - HostName 34.77.50.76 # replace with your VM's public IP address - IdentityFile - User -``` - -**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS code for instance) diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md new file mode 100644 index 0000000..f6751de --- /dev/null +++ b/_partials/vscode_ssh_connection.md @@ -0,0 +1,43 @@ +### Virtual Machine connection + +We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. + +To create the VS Code SSH configuration, run the following in your terminal: + +```bash +gcloud compute config-ssh +``` + +You should get an output similar to: + +```bash +You should now be able to use ssh/scp with your instances. +For example, try running: + + $ ssh lw-de-vm-tswift.europe-west1-b.wagon-bootcamp +# $ ssh lw-de-vm-.. +``` + +To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: + +![](/images/vscode_remote_highlight.png) + +It should bring up a menu: + +![](/images/vscode_remote_menu.png) + +Click on the name of your Virtual Machine: + +![](/images/vscode_remote_hosts.png) + +A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. + +![](/images/vscode_remote_fingerprint.png) + +And you are connected! It should look similar too: + +![](/images/vscode_remote_connected.png) + +Notice the connection in the very bottom-left corner of your VS Code window. It should have the Connection type (SSH), and the name of the host you are connected to. + +**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) From accfaac57921490c044970b94ed81d427e75ad82 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 16:58:10 +0200 Subject: [PATCH 19/44] added image assets for automation --- images/gcp_vm_stop.png | Bin 0 -> 146498 bytes images/repo_overview.png | Bin 0 -> 96397 bytes images/vscode_after_ansible1.png | Bin 0 -> 36018 bytes images/vscode_remote_connected.png | Bin 0 -> 96743 bytes images/vscode_remote_fingerprint.png | Bin 0 -> 45296 bytes images/vscode_remote_highlight.png | Bin 0 -> 47871 bytes images/vscode_remote_hosts.png | Bin 0 -> 41993 bytes images/vscode_remote_menu.png | Bin 0 -> 51685 bytes 8 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/gcp_vm_stop.png create mode 100644 images/repo_overview.png create mode 100644 images/vscode_after_ansible1.png create mode 100644 images/vscode_remote_connected.png create mode 100644 images/vscode_remote_fingerprint.png create mode 100644 images/vscode_remote_highlight.png create mode 100644 images/vscode_remote_hosts.png create mode 100644 images/vscode_remote_menu.png diff --git a/images/gcp_vm_stop.png b/images/gcp_vm_stop.png new file mode 100644 index 0000000000000000000000000000000000000000..45525ee0da293d0e0aaed269c5e25d51ea80bc3c GIT binary patch literal 146498 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俍r3FhP;KBU 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%0DrFWQ~lo?>4@r&AqCoc8l*5PANkY|8p15WPu6 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 J)F|1!|6fzworVAa literal 0 HcmV?d00001 diff --git a/images/repo_overview.png b/images/repo_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca78676eb665804b10265d892940ecd26f798f3 GIT binary patch literal 96397 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
hq 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 Pz9%cG__j#m!{`48I}Fce literal 0 HcmV?d00001 diff --git a/images/vscode_remote_connected.png b/images/vscode_remote_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..fc35c6f78e8f854d813ae1bb9be5bab6c4f6d31b GIT binary patch literal 96743 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 literal 0 HcmV?d00001 diff --git a/images/vscode_remote_fingerprint.png b/images/vscode_remote_fingerprint.png new file mode 100644 index 0000000000000000000000000000000000000000..a96469656420bc8c6b24a1d99dd0d3b08226483f GIT binary patch literal 45296 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
w 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 AAOHXW literal 0 HcmV?d00001 diff --git a/images/vscode_remote_highlight.png b/images/vscode_remote_highlight.png new file mode 100644 index 0000000000000000000000000000000000000000..2d608ee4778c2304c669cc730362ff94a2394d82 GIT binary patch literal 47871 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 literal 0 HcmV?d00001 diff --git a/images/vscode_remote_hosts.png b/images/vscode_remote_hosts.png new file mode 100644 index 0000000000000000000000000000000000000000..6e25b1f7323be0ef9642f13076e1982cba61e2d7 GIT binary patch literal 41993 zcmZ5|Wk6M17cHS6N{Ap`N-N!sK{wLfAl==af^>tlbV+xEbc1wvNymY=j^6v-_ul%! zslC@;G3OX#&OJB5GE%}QPw}3@z`&r0iU@pyfkE_wfq{d4f&jkx?vP0UULM(g5S4!d zn%fioAn+O2PEgrS&eG7%QOCvr#>m3b+grkR|r+V5%73uo5@A&u@5(l!WA)xGpAih&y5% z8yh&t2s}h+Qh6A8<0{eX3aijDWJ7RnE)EJmL63^0U{S1_lOLiH(iDa^q{% zEG_VYuFiUxAp;Hr-WSlx-Q6A4n>Ph2izCA~Ez_3b;8%h0t?5bFKjYuU6TiPWn2Z1Y z+vaC~fByIHGQXi05*TvgOOFT%2}wHYb-y{w2WLw|M`p}R{-^(6-|7mM%gPw$E!e@8 zQ*q;LEweJ(4Beb0`M=`WcIS#&b+e zzv(@NzZcBLom@(8u-{Xxlu&4eZaQUmONT1kjoeLWpmm}vhI5-VQoS4AkmWeF=L5Cd z!(2Wm7wBmHha3d4z+$1E`uZ*Otg#PZ+~2;DgcET33~!Aup$H0Occi)=*6~~|`=;1W zsT40(XJ-0PraAcx3=FUxaI>()2opK`9UmXFnYXxI+r-gn{K_?l+}+jQ9yZh+w?CWv z0SPDMzFH%G_}=203dcnTYsQdB-RywAVRQ~tgP)G(#>apr-p;eHH*b8jqUqu(ysrwK zVgKVtkCyGY8n}?53l}NpGrdR7z))7$@fS1705_H!7+ z%Ea5Fmh?1U*Quh@``e@FxVWiY_n~zD^a#G2AYRvt36=X+c(miqWXq`JK0Qt zZLedG&{R8Njbyi<67bYsfA79!&`;UP>Tr?IW_SNEGfA+7bPz%@D~)2az8ma z2_xoDb6j$-8Tt(!^Kl27Z9i=djMca#yH4fo%nxI^L9Utw2YeM36-+FwYL^yRSlIRT zbpoX>HCfrVd&uoXLt92}f#)3Aw9R^;lcE-DevOzy$kw{K5QP3MqH!AZ61 zC5DCZ8g$s#*VjG8TUH!W+cVOS)7^fHW|cx#v0Jvkx(5UVFgYHor-ASG9b8kVixl6U zZVu|5taf2yW7pIUDyF|`UY0pFC9^aO{&sw0bbN!TNbc?)yIk10T>Sl1a7by^-t#%i z)2FMJp11f&NJubtM~kU5Gc$CddBr#9dp*}%=~}05KVzuv53zznLrHi9J$F6S zfQk;*((86TY65;VH>-XAhNo6)db#`_(o3AaG z%sC;<$alh~Q65=kT(7LCuxeOf9nO8(SR9Avd!;RDp>*{@OOQiH0xr9t zA3s=r{`^@_GFBZL8oKuLZK?kDNQT|s)R(cbPYy?mgJU`34f}41JkCr?>ei1J8XS9; zmRcxsH~Qn*odcDWZh_4)CQ5v1=Cj=#U|Tq!Qq23ssRF6v*6R*iJ4^`q@@1osGF^Wx zTT}xxHN|9C>HZJ-^ah)nlb1n(F!+1PO|iy`+U;d-fzMn=nyTK!_?5$sa!@ue9sEW3pST%&xVb?2?6csOUO7LKD&kfRFO&;0cR9_^VMqYbWa$r+$pT>)v?a~ zMNNynLl7l&dJ@TOUkv)=PHI{pD1jaCOEsHj-< z9zUa^r8QSbE*68iblX!jYq{rt^T7pHyWzLT9Y&t4PECg_Wx~MnmhiVzR~Ppi9KLvX znDhwL;v4f~=zO-bA}UO$OAxf!6D1^4xnle28o~gFlzTpSXnI1<>588;u7gw)ha=)?5%*x`lS%0!O zT?&wLF<%t(=JuA^epg;7f=F^WjhC95dc_}GQ@bae@C%XSM+mdw01kz8nuL=R2V3$N zg+j%XlOE#fMvwDJC1!_x<(spekMG{W1fmfec7?nwQmra*=PJXB@9zR0);&|M7a12oKwo%7)CrYo-Es!gDH@?L9PjjWVs6Jn{k|x2V0Ja8 z5>?JTX-T`sjg35Uv})b6M(Kka@mfPQOCF(p`l}si{Q4LBvzVBe6K0opr^8Unt8_j! zgc{T75H~J|6$#We4;-RnW4l7>o1H$eJER0{mNeDYa#+;wP#~ZZ1oi2^=H^arIBIU# zY(zstLtJk4hIhMK2~6?4zXq$Ga=6eCot)gS^>Cw9QBmQwHr%(;5op_i!ah=}#qZb}?%N-NTspcz6ZUCwDv2p08P0F!}lU!5L0FIq@8J+cMZ^isP!coDPGm(+n2# z94?oKUq(NZ@$;uc_n_1hQW#AdAFYzpmVVU36E^%nLlE~$gE0IL#RVc!&wj~RrD|g1 z30vwrL;Qe_&Y9x|*7@!v!gGB}&9Ydf+Hf!lmGH4bHuLO(!(r2U*%tw2H6xH{wF_Hoy`R2?jEO1A`E*kjFf#yM*jg|Uuqex*2Qq+sP^IIn zrD`+3))Qd_jF$&;HoiY!7YzV2x#6%rba`2O(Rqsy2Jn!OkPyOA<0&do#+_YVCqM>$ z1^eoGf0|zHpq9l4Ig`VpQxEFW&5u^bW49nk_q=!Zbw?h&Q~~D!FTz0%NNUI!;y&WJ zxjfR!ORcS~U3+nL@QR!~NATs0x3@QqdhOSuA{vW^1GYDB-XyRXzX-*q-vqm3{yW$E zVrqn8UUFx#i5seCn2m-yEov|b2nH-YPVo=xwum-|)0f`MvXzieFMfOPdwhDTw>gkl zt4;@))|+_vw$65I_1p!Q--G9LYj_JV*YY6y()#vjmb&AD{k-c@6V$0t7IoOQTVY^4 zZs(Q&%Af-=t6ZiHE0-&gU)P)>MJdg5^62s7#|aV?7C;Fc*6-1QMPHQK&51Ma-%>U+ zqX9d$1@@a82;lU)b;@~<+k>;+$->Pm!Dix9hBkgT;dJ-@2ChF5MkJ~u)uyUgH&2Lt z$43o9Kwl}D6_u5VZ02}ES>=YaqglcY46ivC?9a-E2?tB7@NwR}Eo*c|L@>gYzbPO> zAQk9-ZkG*n8gI$QP!x)$WuSmCqqMUZ6Lq(h<{A$CyJ3?NkR_HmbV@?u1bvx;p=GmX z1e`X0mrI_+fgNo@=%idUi%MGVv1t5vWt+08EKE4a>aGV>G%6K-K&se+B|rt{KUJ*8 zO%oUA0-ThZifTD0UQ>4{g%cT%<@?Yc)Go=%$r~XTa|FCDF+k*Lx}PhouCDG%=xWTx zP|GP-nY>JQzrcO@@}=A5g5w>hVpnC3Hk1CTj(Xj6Oz3z35Pa?Q8i=&)+}s!V z_@U`qg%2twl{XJk&;_>_Lh`D14~LD3ja_kQI009HoKN#y&fBWn4zdENRh)$;E(Ocy zOU$>XBKAig_2On7EuwutV_##oTYNYT4(i>>Yivx(5{{VS5s;z;P;a!-?k^xD^hsG+ zL`UZp;1+%G1rW?llLtV7;=u5G?)Nz^_s>3#{7AChvmS6txyFFw_Ndgg{?N@Kwppt5 z#{IYr@fy&GX_^w+$*&X;Kj^UFIRkdwqXAS;nACecXz4M&EK@!y8rL0Acqk^77agzV zk;uO2Xz0cibw2W}8SWoBplfwR#G2?s&QqhZ7y-!BMk0@!d*73b#>lGU{};LmP@ zO#J*UNh|4yXhag$)+b0P7;}Y6^nk!33RedQ20E9P(!YQIo|Iv}#|=nC(q2zkL{ie= z_j(_VmS!v_4znS0AS$5=3(@E1VGw@LHoJ3^3Ww{18HeF8`hYtt?Ftp5J~fagQnd=V>cx1`>@-5c^xjEroP2G-yZQTQu?QLh#V zGtoUP3EiO(9 zV$^4(QRA{knAwv?<;o_T543OI=q@%o!_a6pCcwfY98bteTOT!DR+~_5E0TM;!y1}V zqsi$UqFPX{?{~HcOTTFkoCrH|Tc5YCy+zHMzI9x6{PE^_`fy-rg~^psIvT?d!&388 zAUJ*)_bU6gwF1m(m1JL-fR(LU%xCbf8{g5NEKn%YY)S%Af5Z~dz<>{)g9Cwa^a1Iv zHXqlfy$nU}acO?@v-2s`;W<^w^SbH1uBDdqOUWM-fT9xk+_^ybs;{qqe474{68lz( ztxnR`9RZ3Jr-fRO5XVL5KtI1n)fNk4qM}GZ%PkW>Tp?m>*rD(2>>Rjryqj#SKQHVk z1Q{HH_+xVsVNFDQHnU}LI-&;wUgO0e&g7Pw>5^mm@bt=-xZW?D1J<03HDF*QAa^uq zPNQ7r1(X&LpnM)zD~JflIIVzz=jl$W{$4kyzsXX^rYqS=X3W-Q_SBUvfD&!5UB@JEN&)HzFaR~^MKJ09? z@W(CqKNaT)G-?(vjUevicXUnV^zx22L0!HH&Uv`MYyqql3MLh;`}-JxR9Z(M8nfG# z)l`Yb-0A@UEc z1zE@Vk&zLEx4CLI^Glu&yg)YtaT$Sv&o)655gM8W@EjlwOP#y0O~ZoQ%}$;~5(`r4 zv^WTMW@@eVqUTtqjbPNO%~q=CEc5`3clPw00uBM72lNv8n>Qhmq{6>}d;B;ZmA}4h zc^HhA<`b2WKz6-6G`DMVzrC=YR8U&k+ESvVCLktWGJbgs0&ks}G93^H#y@_BC8MGu zYG6Q~lau2Y7zniL9JO`I_c(P|jRW9sD?nPB4ibt>R0ZaC z3)bYp?z`(#(2=XtMy!(Rq+ub&VwqdrBR9S<3q*HCUa$ORd}IXp%>~o#^R{{7tw$wi zD;;Qav7W8gqcm=thYF%gzapajI#ycsnMPYYJ-w2y?Y9P#g+ZbMWU+u}Gw6%-piXXY zZ8^?&XfrIIUONHll)!3=)z{aTFlabnXd7*73Aex0k`B^fev3`67=XGyKi&-PbOjpw z`OBAr+S(+bE1>l$Bof{M6(^$rGCnGOjn1by4B9ZjIQiUfCU8H@u2?ZxEw?5)^Yh;w ze|+)cMFN-o8<6Md)@Ne;Jn}7R#Rv^>Ga&IUprmnloEU)p`1$*f=1Hex5!VcFtt~h% z834Hk_7wvMM+EE~G`aLvv8Z*!rpi>SYKs5iS{f=G4Tns}j$tGC?>V5k1|1z8Xcp2hAYdvH zjg^)b1z=2Z&7v5vwrwCUfvVPP^@1H#d|#8-a<@Sbj)L3c_aqShAJSi1Yr-udw3gt5%D29JE^d_z5PQR zz1EPNG;bHkID&ZH0I>PIRR_wv{j|o}{%kbRApi=00tLcF6aH}9^1y8|3t;pLfagHH z{hk$9sze%3BKJ`v28hMX*zmPHt_`vd+|NdZ1q208;#= zC=iO^BO@~33g{moN1l~tvrI4`8{7`Wa(@^uvl9?PjLCx_eRtZ1NNjby{2m56O5V%) z4ydoi(Wtb80XYF3kqGQ4nnJRDcsRnx2Ts#z#XqUR2?S=;xsu70(m$!BwV*TEGIr%tB{RtZW0Ai@^``mnU+p6lW00m6?(uPFgK zqI&xl-+ zo2R3sX9v^7wh@~4Q??7P7OsbiAbp>G3?jKQ%cbU|WS#Yi=@Evd$$pcEBFHU>gX*wXp z?V#6Uq25J>EifNxQoF?stqf!~uaUfo7Cxw@FmXefp4<*mAP*UK0kO?B^b@b+&-9oIFrJ~a&3XiSCuj=;wnpsii>^yp;52%~k8XHF8TN{rEhSBezH2sFB{fb`0qxQ?BJ;Y{in8%YsT`Aq7I zK7>(7+%wbnV1JN1HuF$9cZ4eQrgo=x{A&GX;EyFnhRgj4C3GtH+<`Vds2&FSZAQ;~ zH;@vEa5V>Uq@;zKrsfa`PJcBXf$Ur=(3&7I)WT-|09@#kjLb-``E;>b4-hufnOFEp z4;O#{&_J@za=bam)?Ne-r*(KMXS&Bx&f&ydK5oDJde-zRmazNDxAjsGQs<^Qtp=B% zzL&x`yy>B|elPK8D((H1Qmyq&=oOtFhL*mg;ESJ~v%y)xLz-gY#paIF)x@OkuRD&{ zv!e_O#cqF@6On|4=1Pz-QN~_Yrxmak3Hf9RePvlCcun)_(T&nFO}T7B<(EOVQ!7{@ zQ)JO#YXN_iCr=;MjC<4ahtei9Q~&m2G=yWOqte+JqYp1!uOgGsu}PPRD;dZXUlcSY z=o2kF#1w~7(~S~AU669nR0-VZZb<6GlQf%uo=IBdmmq=jMU#gPvHGrQ|L2TgcvEG> zo&LXzJ3a{F{Qe)t7t2|~)Wlu)-N7Qm#zcRwSh29XH-?qQEkYX!w6OQkkpesU>z;R`} zI74y!s^Qmf+G+NMgsD?bVa04;`nR8cyUnB zEvb@fmDGhpyEwE0lw|0hQXFw4$6SQ^mdb6LJTRU&WReDkA0`V*n(}ED=3Bph{8GIF z8>XxmB@z-rLDLyDZ9wWcjWx#nG+ZGY4=Ggo6?JzAIa$y<&+k@P(aGhBKL#?Bbke?D zjoV)78+H@!rOmS}YDP;B2jOI@&-L~eYBDB#M;8sldEre?RaOx7OGocvQ@$F@sSUHk z4}Yy!t2qVP^&D1NB!MY$>Sv#XVVYXL-LNbX-sUF6Z~xmV{2 z9(mV!^7H{)QubkRA)EY6+21+o=fIg|I8r!5` zB%Lel>;*!yDenUxnMB&p?XS<_tmQt%3|^ol=gZky97?;{ytYQik`O`*_koy6FNrxw z`hRAS#s2boCB^E4gjdh|i_MqW8w9SGJ^@x61E1f(P`!5F5vvI2HcIA}F4+7=7>_AF zQ!Zxgc;cW)H~ii8%e%pAj#cQnn(Ec+Oylg)D)KKQ@;%|!UJSS4=~7UQq(7~JR~uqu zvs@HEhzx{~_Au&gZWmBq9MEW`d8clcQk%{@MFn28;l1$Vw-CE1F}&XNsW*D}P(FaO zp>sYqIH4}PnIVzF<(FdcwwDGz%bqGLIuOGcr7Z|wY1Bcnbb!a9QK;x+v?v~tV8U$B zw1U7;wH@10vD6Hk2ddgC#aEl~)E{VLy(h}SqDieYRBzu4(Q8H|w-fHEG&6<81XG7O zxVPS<5FfD|*Pt4$P6&XTUKx=dh2#91h=QDnW}?HZ%9rf6>a=%%(F}ymTrn_M0NFTq zoXW9h7`l62=uvB1e*9RPbi;h}lhJQ~sa1IIl!{q3SX4?!JtXwyTP9;F;?Kz9+N-r9 zA#8aSEIp`kR4;lW4B$`~Z!@1TVDLJ;?t8^)CbjS`e8G3rtZn@S#_*d@`&mv=ubBzQ zRPHaYJ_Gd=X_+rj4Ry;m+KWT*PaBE(Y=Wt zlP6`LWQmHFRi1?sBaW8zYV_de&)P3W1FIvQ>J{;Ms#s~~OhhM<@MV!rel#HR zYm`WDiF{lMRl9Gnc4+=4q^46+yIqD-O_82-ae~3(buh>j`6j8;YVfw0VPGu580(!l(5nWhpYPKGlZ_ ztsCKH@Ux`$s^6>H>XJ3ziPt>uS2`&oblM+1=uL}^_e@p{6a1s%@`prm{M9u~N(V*VxPnM7mJywt}N{no;0*;s0qWkV&l}jWr`r@7wDRrHjZKBFh zI;i0i(L3?7Ra6`5)(D_`>^C8SC1BitO-md4Iv%^UUuXz>Z$=kw%cr*Bvgb3)dw-0c z^6-oL{bKGwRqM26>*X^TrxO+yglg6_baa0+m3UF_{%4xlf{8o()&aIs+4-8>3MVf6 zv)M*iI^kjMzx2P+*5-!ibEY>Dsi#$^cnQIMS+?d1C$Hm;nT=Q=(cYJKYxJKVoZNDr zWUVB}&kXRByWRipiHddHnW}Em& zh~aA!0h;%m_{ym&?-F}Ld(wovckO=DlH!am&74_-Th-7elAQmiSZO_bJ(ENarJs2~ zIcw+@9i4x^r~?yQ5ouQI$Il6mJxyOv4~rC4#-dYpy?>_yxu6kHhTFmAi^MIruVHYh zWQ3(KCH|o9zfN3Z-p@K4P=}@%o!WG5UwGXp$cY&x;rIB0O?i8(OUF_7DN6ejS}D}T z_76zb8`0yM9i-Facdpv62H>iB1&hT#$8MOBvl?-4mQk&)(rN4JzVKI@s=S}ME7Wvl zOI9+BCL)lsQzsBrqWoaNwa0EGr$M8+GSgolQBBBBP(kkT8smc+dRT||GmKa7y`ItN zU^V*BQ5D#}Gr(Nu76~cS&3&Tez%@54s?$Efw{B<{Rle1;QlOSSxYc(eF(u=I5D>{@ zkI+}8#o)s`@(5)D8QzHimB;&i&t%N>S`cYBx)fpt zr_N{1&>DjJFyut2RDWVuG1V_tz+HIAwk{q(aNW(HX6ZdsiBw5-E^S@2A!HY@(=LQR z|K#nt=dvg#(ET%KA1RcAjxG&pI)a4VoZOgGgE`F7UynXtoLz3>u7LlyOWRBorp5TQ z{9A{h=@~ovc!RtX%@Y6nkE-a zyo~UIgv{@GsqcR7VmH?1Tm&93o#nL0=06LP@{{G!5AeR1x-GP+?0J0O2WbpU>{-T( zV6vjFL{4shhcY2SwxsRznGoy5+vlUp&&L)E=EE7w`kGi~0}7uf_k7S7Sg04%Q^s^J zi(VRvttSd3lolawPkOU<#%1l|Q|9-B4}KolVBYtcIsNn+zZxp+Kzm|rae zpPTj~?dKTmqY&9Ltf0TDHLF%dGNLcZY%DZ_AwDuNZBL+ZIGcS{qXCN-Ge+ z?zFi^2v+WY&dBGx`yU9iI`;w_FupgoAZ5pvEgK>~;H# zp2(3UpT5sz9A;E{JpyZsRmD3$+pDR1$vO%K4YX*MqVP z>=|@fl8r@w=3ig7ejK{c;K+&+6%A@PVN)!|(6{)JIW_M|Wi6}oC^@W0xBP|u=wksq z^K~qjR~#X=8IW>>WCl1PIR+iZzD|Ev>VabZW!u}gbCqArba8pP0vIaMv-&Q8>3IXAPr`P=<&u8+RO%YeuS=eCgNiJwpxW}R zV5Dc=`b8m}G&Hpe3WFuO_(XfpbvwdSg%zJ|#;MEEhBF7ME8%oR>zbredRM*ZH!NCF z91wybr4XljC4@%AzC1`u+99R9%0U-Wt;>eTh&QO*Ud)pGf^J5-nK5LB3PYxQ(f;l1 zW|;2TIXlx@x2Y%-c9f~u`c1wP#xSa)<&dfV$bNuRZ{LhRvk9i&T00UOF5}}s41T)c zC$0#%oQt^;g*oY*(0B|q8v+zqTIlN-qYm;@QZ~M{^{*swkc@T}A6owCN&Ik>>)pOr z2U+K2VR&t|d(lt0s-+IAS&Pb*az69S&dspu6HqJFsnof>t@aso`|<0&%_>z19{PuG zo{xv3UNem=5+!Fm}Fj~J^gKImm``TiTVp_33Q*BAXY==zEo+_;EAHBM7 z_i6m+E(-I!9sb3@WRV?ZRE*tA_6wF(`E8z}_Je2V#~`m3Zs)}MDa z+cI3=Y*pWa2;M>%9e3|j-*@hOEABK({S<<*-j;#~+v=~X@(=UoDeRW`$(22k zJST=PAaAX(j&wVI()XHPB$?#Dt}a=W(Ej~cqR|-HTYlN0-U@R+uM-{`Y=*y@QmsO( z>5%g1<{CRKaOsFEkBVI+i+VxHWUmh5ISYbnUNbR>PercOGfN`1>e)IrXM&Fhg?$xs zy<%#jil!ed3$8PZizMtLQ#b-lF+M<{MjY6kQ?!;wt*LZqH*W$6tvCHMb-QV$l~e1Jjl%@{hW z@|>C)VS?&V=F~TTikUCJzlluYb7ipO+tKe`~OzWpl5{8~!aY zmU{WA0zdt|X9%>wV+Z+WiX6;zEExHU!D#^#wYeIU!yq{Xo{-knWeFL)=s1Le-P61u_JZ|@`m(W4D{XPA^ ziKS5d4Q;`X|1?g?zxDS2>=$^kNs{@aM*pU7pnum{G9Ez-F8^!2#vlIXbpGuIJ#yU7 zvxkkieIy+cc9ljuC)u@P?pAL>93GAWtwjH?t^b(tMp}N3@L`uF_-jbJ%pt1UY z%{WIY0e&WQdTwBCCMj@?f8`YJvYhN##s!a?kL$m~z`MwCK}s?&wKn&l17fEE$?&x(^_LNPP7n3{_4a7(Pgpwy{$`K=T~m<`DIQoe zWb%6>J)HT477M*@5*N5bES8n|hVV;NC2|*2JK~=k@jYV@KlnejMgN-$Cv%E2+{{dL z`kn5JECdHryVy7~FY7p~UX@RlDob(Z(1LxNfNfrzH{+%FgJn;i!EOky?^j|7Ij7pY zbV})VhrJDoc=Ec{Il*0RX{(BTypP^8do&4!erqM3qU`9tLD^-wrwcxhuY*+f$aar- zTxZ>GQHF5=9Ym7X!ML_t434`xn@x2Q6t=B7xcckTM*41+99CB| z?Tg5v2a-eGsT|&m=p8r`ToH>me79m5!u$3EO_prYOpD7Kx9J8;D>gKwMyJQAwzU>p z8ja51@}UJlmyyWV{8~=Qw@69=BH}raKXZ z&ik0Laqt^4hpKJAG>Cqp9qCW&P;SK7UKPG98ax_Y*5SpQ`STFZpW)d3z(|LOKFuP) zrHtuIO0spTAt`?%#K@6}578xFv5cSABzpJmT1gr1+s+H^UaecsYmBJcTE{o}ff>T> zBAGU0&ecE4X;Wqnq-e07!4hyx-RbN*Y#Z(%u+;y-roUHt{ul71a0d;ndH3B;6^S(F zx@R5H@}lExUy6!0i9&Gbnpr~JO|jV%yNg4*Cq#<=XXInEzYLyyhT7zg2^KCb8A}OGrZiq zBZ|C_{tgt`^158+svX!XW?PeaAlT-G^HfVcZ$j*5DtkG8!ZogRqEItB@3QyVr#d%k zbf9eXe*?0y8GSwi{gmhR+g;pweY9gB!G#c1J#f=d91~El9yi;Cgp(WhJJPO5t=a_WgxTn-Hr* zwf_Ey5_6l>jwPB6=_MN849GftYEKM8635*MPp-SV<7`R1XUCv@TukLj#Q2QU2lT&2 z2L6hu8UJ0i|9LaO(ZBRN^oW-Zc%UKkz{GKXT575FUY05K!Tk6C94ggb3~uI$lUkF4 z_U#|IvB`a-(VsP*M8pSuH0E!Uawm+3xnF6~CkooCnCY9xo7)tcNxp7jBa47?#(!;y z2OM}2cYHue+`h3Ev^RTf5$3(HGs*jWp8ptvcDVMUi99jA;-X~;^_lE{r-64M!(aaK zovZlO#rWlQb@}w|7ro7OA9MN+L(RU1d$aapKj`kdX zcAB^4pXb^nY&r?1CSUzE>tH6^C2)5LI?%9he|SuUvVb9N^55T)+_9mixI;k6_Q{Mfo+-$4s=-mHJeN%ZLcUAJ`dhPLQtOkf44}C4C_Bngh|1| z_YCSTK!VS9mLZQ&iHDcAG~2(TE=Hu7Au!zDtJS(IzvHgKZ~abPb3EpE>|k*zkNq=- z+fwK7_~Ov=-!A|0WTdz@coBk`td2`tMJIyjA>vjQ!e+`Hyo|6UE2OMl=_TE#8)LFt zzsHv^7PVkL3Z)KzZ+m~RaGXCl;VUkjI-K(}^dFWILHtJ)tV`%{#XH-UuHGDD6!M@D z@C2YKHg{8E#LPey2efg{rd<8q;ny~XPl#G$@JmL0rpQXfx{9>W;j}3smCk=2n^{j%Ew; zqpp!Ju3TY7rT6^WA|0Gt-uB%!tiiYA?cNb{OkHVnx6ydJ_h$>OE0V;w&~qs^@HGvW z3M*?N1#hoz3q4nl19lC@6Pdo{YkuY`X$@H2=1v=C9o~f)|c59C^KJXNXp)aKN?v;{M*`z&w4eFfY$`eAy+oDi?O1 z#gQ+uP^+VS#lU8%*0(NL5@kc9)N@R0?YQCe+ScZC$3cl3N>9LauluFNJr7+1zO zMOM}AH78$!Ow-ch-DX#Thpm}YB3idX4}rkXM#{d0W7Vu%$c|s(m1L>eVaxf;MXrfX zor!VBEBl_IN_Oiak0^Uv`jtGCwD^^~l`qp*yK%={{hMqRW(zR|S8y14O6OhWdJvP9 zmth6WDfZ8ilq8K78ipY=rTxTu3$$BPyOks_N|F@zQe48&EI8A>SxXTacH#3aewCkcpLXqud}p6`SoRXQzq3<#;AZ0y-W->!tFUB7 z`B&Poy!-oHs9c!qmPK^}g4IshZl?xJFt*S*J6TeUYQKkz4vW!2zkXI;h9aCu?S@61 z7I9~{5w^|H758=Dky6=>tI6O4eyeoe!eGH3ywhoL;1kKZXz{c`3X@I3#+dozk(L}S zqu-LpbrN`rZ_$6f4HrkmDzg@cO>p_j!IQ#U$|LnKTKOcc_N(Ah&&gS8a7^>%Q*4P8 z!Q*w1(T(mEZ)wPm>{Q)bGZE3gstY4l{CQe=M8;u^1<7k^S3~q(K6TznRI433#bqC8 zj=pbkN$Wz)yj~l3WN6@eZ}x@4+KM`~pe7aaw3KUTBM1AaL`uanh4%gK7q0dWo(w?wpkwL$~O^J#;>vFB|B) zy4^Y*s?`(Kl%tB*#2HFcBFcQ&-gzYLmZHWUOEh=SP`bz#_?58|370w0bUKz;O>>C7 zUvniY*!GEqRm<_9>oD^nTH)1Jn~iFh?bj`0m!SJK%N3t%Qx3a(JHEPyJA}n0UA{$? zpLHEWkdrFSEt{Qp7+a_%RWuw);vLUsDzb23E{9mvxm{6TiH;-PPrhI~Zwi?KG{X6(P9O^SR9%KQx@AT`_Yuc(o8c(=$7vmqoh2OD$g6t**`2 zXMS7c+B&^qmJ{VU=3Ao}dS&kAvijFd zDKR=_x9^@KRmDl-VRgnyHdwPy1W<=_Q}|V!#46Q#p1yzDpMrUKn^eR0((1<)mu)GU z!Fgrr@vm^*c_Kh*WP42lw7y&0q{>pB6@id3SU(J33L9 z-s>P)9?<0eC`yog8^>VlA01=7W=f9SUp^;BeeTszl+a$WdAmB|?W=I~9{!dWJyfMQWs{L^EJP!|* zj+gIc7ccK0w0bqgD++zslV5XHWbuo1azx>;;+nbMhb9wiw5E4MY;Tf{sXrr3*fog3>bYEqTMNMA<*FGzYH)oPx6?3I>fPX+%(e zTA4;X8>k+(->lEkKIJ@^cX`LU6MAOX{f@{Q{O14|7>2ZR1O^zG*6+3|gg%+I|JDK^ zhHH*&Qetf{veRu3>_1lJ+DW-zGygajibbV?EuZd^9ye6`O~cb%b_|1mN(mp!&hA3> z#%df7vUF~1f7IFk%eErts6TsnvT6L2-O_M%-?V+h!ia_zM@;7I%?bBIF0tcKZ!!Nj z%hLHmUc}*@Eq?WE;p)_JN}KHl@y&w6ZB6&F9s?h2`aR2}LQBcm3EU9(h1Uto z>H0hi1IwfXuon40nlD1Q7K?3fGQ(5qi_(YF3+3JO7xRdU@D=o{CRy9{C9a0@DzKt7V);0!?7AA zxACqW%j)bjamWR^a_RKL_13TD1M|ELEy&r{jk!^L$!sQNX-c_ieDx+s9U)|NW z`yKE8UzKYg__2-AYU=%)3~#TGb~m=wrpd`47vEd*%e(lwnPW%n;)ovBB~1;y=iDww@k_FE_?Fvq{MVn(b2H97@A9P_4D&?~^adeK z)$M3;y@3hqvuw@DIP(v{ldO~Jds(+iQMr4O*W(+P znlh>>D=)40HV>ut=0IAdDD)zsU^L9j?j}Bi+2Wc^znD*W5|Sa zrS|Ct-SCbo<5IZI zx4=CrGuEkJm*=2zG|7`OeW@|gZlpDF;ZrA;{+Y^n)s9x(F8%PJMpc~nkh7$kocv}1 z&1k!~d9C2+@=A^Ite5{@nfPIviC4E}u)Z;U@AIh{#OXlKg={i|tl{HQ5*ws?3XxB) zTx;W|dU5eMAugLMhR41-jm}kbZ)|wy+_9k~pXcKez3MlAxw(kz`_SRNtyB8lbKZlV zM=c!RrlraE{L^_$#}EyvW-X|kcg@_lyk{M2rK}y>H(+ckZ}k zZ#y?>td9h?aF0A(8J+rsYuSA^Zu6~o%*L*Vh#5J98$A$4NPA!m}U72XK&s?JX`+(LBB>Pc5}?O4EE)4{aaW z>kE9(vE?n(3-g|B?y3>KG7V`G-}Zp`Y4Xox=Fm5PmyD?9M_WpI_~yaUB2HqKHWJ6L zKGKe@HBlHbG*v^v1^y4s(&(HivAkN>eK;55=0G###usbnKnrW{7PpUZ32}UqHJne* z`W>-JWc9->lRH0Y9pu*j!u{s|@bwo^QGMSZFg#+TVj+T*3MdWIje^o4F?1;o9n#Vu z5|UCwcMl~oGz^M@bazQNNH@Ia4t(GL?^)|v&s{Eod(S<0pPiq*@44r+9i8;~Ld)O4 zVDqFDiCFn#NJsL=1qy`LR_Hqm$yfTGhn(2{`zGLI7C>;k&EPz6*9%Q@tRmW1Y)*%H zBWl+yh0o8mAN$Fiv}9F&&P8pK z^mCod5J^ZUZ>XWO?&B+U&rhn`mN9^Ol9>Wat^=s!qU?rS59Ysor& zo3pDerECp*s_14%rZ{BRrNa)27@!(VE^9NDczeo!7}$J87xX&p~Jd^jZB zdZ9dL{A3GmDE+m`WnU2OoIGuQAn(X=EWdPkW z-+KoxDm+$;u}89e`Jq>1D30CFlyVwaagnW?gbB-!P|C_W<6I&T>VcI@8 zt;un9U`*78Yb=|=@}?i@ zc*6zK(H&HLxmL2P`tF(&~p`R{O>ZSBR@w#vSvg82QfTiQ&F-8-BKN=6|)J2okS zRfk@9v5$Isfi?hO!W9NSqI?u!cURaHe1%@&a?GK>2(DP)4H!F;r+E}GHZZnt-ya0l zdO#O%kqv3=^_6-TYuyY=y{a@n?JC{x>a+_#=3rdfeE;#LvwofHqG@&7sd4x9zR}At z9m3X=;f886Ss586UELJ$)ri@_x1N>FJcnVRl+0rG=8FcgyyNMtKH0NZZV)BJp%=r^02UQ>P*H zETH)F`MZI>=dWV5-E9DSXKjZrwgYT$Allr$R11Esqkb_$uyzmXxa_;9iVGOE4%Zzh zgx^g0>WaZXzx1(0GtlljXf=g%0YY-j(f9@(qgCsd!F?9>>$@03%fu&R2++X)M#-m# z;3spul#kbp(Z0OVS34^3H+0lL<$>Jq`Jv?$7;pl*qa&0PQ z66Q7K5;p=qDdU`7emrKf&ItYLf%wBr=~xBUnZh1-?5rWW&yQNdSFoF)2lr;`j_5h7 znZ-3iQ6z4Em_d?mneTZ|_4!=>ZZcsMHi0a2smAHXg(QKLgF>$^=V=D7Wjn<2J8DI= zPUJ&tY1y@jH7m6p@vJBy#;^s61i*`s~X?{2w~ zvKFB~G(JUCgqV$S>ms{YAI?uuMX1C$gE@+p&?GbcWEfG^_fez! zZCf-a+9+LAonuwWH1Tk(_^0-QGPn13S3B)AaiArMDlIjG(#g@ya`|QXZ0(u~BY0Jj zLcD{dd?5icN72HpWMr2M!KrSO)tSBMyf&ZPBqC1aaMI6YJUjMqt0|bwuKrIi=0qL-$7VJ4Go`CV@T)ytTHyrZF84u*Eef7eo8Xurw!?fve4E)yO4N9nME zq^R=d;-d*733;*HhsHJs)2eai6*;rnU;C{@lmbxE*Xcd#1vyJFvf0rK?@BjIi<{@Jj+|+b5^u1gtpza>u?lV=%eq`2wg$ggH zDIBi*QbZz}rH}=2yZB+al1h3ZpQK}{c?VK00Y}7lWV2|-%rro`^NisyIqUAghS?7b z$PM;CXBDDd(q#F`GdF~S%zQq+RE}nxm*~D6CmEeJeJ6|6BbKcHsbkc ze$&#Kc6gDp<8Ilf3KQ+qp_7?KSMi0B7#a8sFS=WSNs{rw$s#+0K#9y!6YpA%}}r+<3Icgo1~b3u>A_a$e2fX3Q1QbNtl`S}DjtwQeNR2yPKLLL<|-k-h#; z$#eidye`$!Qz(s5a5=12+zx!Wl@M+rId*2PcZ7w>V7x3F;TRp1iL&wbNxTQo_->{B z%Fll5lN3S2_VAg5A5#kspHyq2$Btjl8D0YVJ*ASECqX7l{vw4}ma1GHJ@+w)x+GLv z>y&} z#*4!E{sZ6f6UHsTpfs6+^%BnT8 zj-|Q1bYpJv1W1F{p<8M*+S#UXf!_FytWPdpBr^dkPYNj{2hA$Ga8xbB$jb{%Pg+Fa z35$ahBZ&$&NTt~a)F~*9u^6pVHPj|YlL|7ws#wi_vLBUG{CQhVo1S#6;FY@UKEiI! z@HdLZ)Y`PKqSOeH_Q1f@(5uZ%HAC6RsgQ&*jaR+$*S}jsm?qV%?JnaL5>5&S5B<;!oGEI7^Sy8_9Riz`NkO{q_ zMJGRM?8KLk^w5dD5?yIj&}2E+oQaax3|DrqB5CCe%xntr-ygI*d^ByRZ#O%`(ht}a7r<#e<-TmkFq8hH zu9bt4@aByga-_>PHV?7DquD+VARg1zW_M|M7m#Z2S zO>>pZkV&XVG<45}BlvjXF{NtUoF%Oh_C}Ixx-l2E;3kJrv?L2njm^p~3rhUm4pO|O z)oHW|l<3U#Bf)L?H-#*g8(|6B>A6$__O>RSt3z!K^*vdm#KqexK{oCyK?d8#zmLaG z`xfKWN{iG+wRh5~^G!lGD){isL{kFcc0qBuLq>7E5{NP?*;auSfvQ*89LH*da5DJv zZl>?0vly$RLHHB+^YTr-Kk0rvs{FO9n&91kyEc6Gvo#|9dDBwbRnYKppN9Q@lSHH9 zP8&b%O2JxJA^pmzMTUFclUrOk$VYS~M*4jOxs0v7eet1*tvqlOm5fp6Tz!+?#Q_?_ z?MZqfG}5y02sNafZKRytWXY1MW@v%TS|lx1L36&%NBNd2!sYUgwlQ5O`TRaJfeq=5 z{NAVLi1MoN2NFz9fYr#RN{3-i(t%tTfV-|~1SpMe>=Na=9WgL)@;lg_7?fl#=Gr(U zIVEl2BC|f|2K(MN@2%H7&dmn`28UaL&d+ag+%Mp)njz7|TfJ!agnGL?@mGV>(KEiP zkTuSS<$XSKR7B4Z@q_hXMg=*@zFFdiO?{irR?vJbJvi8S9GfjOCL*~SYr=g6uHZ*& zx7?HEAFdWPIwMsh!meW2)U>*0la!_=i*8xwL+H=Z3~Q$~iAZjHXMaG<8NO4BFU+AO z&03iQ>zOG!H$AVLQIg0%Wa#bhYh3%-*n4=PpufTD-3J7n!mW)yo2)iviuSx#wbJ$P z{zva;%7=_O7=*p7A{PP70!QulM-{Mv7pizMskIL@Nq-ss?9W5NLv%MNsp>N!Y*@@% zh%_wN45Q6OS1lr_hwVv596LrSg74BvRN_h+F(r zQ2K&7`q9i=C6^?mUK&mLF^no>F7x~J-L$=`jh$sBGFphv?9j>&xe}IL)6686hzADJ zhIwkY*Lo)i!~?Anh%%nfpS-(RG%eLGpi3kQ7pJ$=sCfmI4e^9UEGt;LNJ4I=Jp}W! zPx^7vh(o5ky4abFoyC<7?L(}#j=%zh`>`i35Qc@0b&gbH*f1qcj(dP>&6CXUUS)5A zzF0IS#eODP=uz56o=Tv3OTwZ+Rw!nQ z0BKjsQ8U@y6!PA5phk(tw$Y@TGNDvHV)bL7MdB>!3SVqmVR0J+a?#GbN6$4&LZZ+3 zP%UFwFPpKKv^%d=Yu~JeV+S?)(PP8!;*etwYq)9H+&`)ZVJfua;|)g!bu@D=8Vu@6 z$;J2?%PhSPS#o12(xI|S5o8FWY@~@!B|SV3pL-=_0h3x$snA zr&TQwH%Af`GO{m*>HBdY?fjSGqjD$N-!zpq&{P^Wt!4KXkn-A4J{AYQX0`VSo_5g7 zYn;}1rFV4{)fx~WVNn?#Ow_^erD&e^XQl1i@IuHFahZq_v(m8Hu%0fvbFb@@{iUa; zXZ~9(_X}aq)Arpkmzl`1<752_mX6I9C!u!!aH`(b?%}IUH|O!eXXoA9OZ`{X0JI=% zNbZc$rhSvrNj%IexONbXM5ZH=?{5C-LK?lPnI5!x?aUBx14zsN1NfBR$izfZNa&|D zc}Rux7~FgqoUgA;BECRc^K=|8uFw_Eq<=BU3q$RWLws&h;E5+#bG3EYM{8Ddg!+gU}L>F)i5+T5V4kY->HHw%+%7j?3-D%2hdbF_Xk z_{wsn<1!!OM@lrODsG>0_Kw=}(*NZeZUrC2F6wCVCI!i`Nw$?c95tFq%T^u74CxD? zo?GevA*jfl3fGDfR{k#$0?+Wj4nP21PI{9Ej|E&J8vR=K_^(`RO@LuX=qz7)1}^!x z=04PcFnQ)dQ-{)jS_|&ebvHGTO~|CVVHwU{ew>|3bUSl?upA}0o>jx;taU5mBCZ{G zUoem8;B5x^osq1<1ytK{ng)5S-VW>8(4hZE0-t~s#cBgy_5m3p^w7qn-Gx1su~XNN zHTE{QcFV@jxId ztIyI>gv{7Kc10@+d$6fR%Y=b>tnA3L$fX2?~2sLQT5_M1@bl2`JE#_6EEr< zE;lIdsZ_-N@Z(WBaj)usFGm0_Pd2=jSx|eBM$(7uB~~OBlM{J_nc!q0v_#A_jjCm# z9O%Y=pY@`1>5&G^r2Xy5E`b3m8h$uu>1-QS-VQDbH=@74{QYLX$+j|VGE531YoniC zY&U1tTl{O0mPjq~-F(k#HOjPra(_BEB1|b$+oVZ(sxP8AMUT=es8LO&Q2uxMpyl{f z*r-Wwnn*rsw>qVime^d^)hqsVyE(di_j0u*Wyf)kNZ!ddC*6aAqtCWIV@`;Mu83_t z3lFXRxzg#C0;cL|cGIQ}gY9-&w!IAMH{4WdO}RO6c(r+l{+adE4zQNN2DTP6pTm_y zQQMuDD}(^?UV%yeKO@jJ16c|W9MLuz%C}q;Y$McF2Y3JYBFK!nW~|k4_Z(w;*5Gis zuTxDh;faKyCxW)QsMzlCifPt1jZW$xenIuszP{n1+h?5ezwAMF!FlCK^njWm9Gps& z6%qNW^dKYCsF`OabD=9vO*@4`Gh&v#D@+}X-LGicQp~+xjdZwDp)%XaD9E%s{4_s} z_D?L0vaf<|)COnI;sEb3I$QmQh3`h+sZ2Skw!K|`A6-0tYkR9w-H9e@nUCH+30Ikb zPH;HaG1fLJ*Jb|^3T@Yn2QLv5X?s+yYGl}agV#F6f`eO|$y^(Sif~ECO_)|uNk+F% z(^9OEaj&GSEzuU+kDA$2QRzQ0nrT8b$yoilwl{tJA>Vctr8p%`RQ$xwOT90P0hMWJ zg2_k9j?v1BimvAF+joddHjUT4@Xny{Ji&a)sEC8Re;o+@bH;N))VlXCAWl zEs-_0xRRtto&8vram~y$=lYhFMxkZDiQ)o(?@+lRSPs&*wS}e=#U2w@XqsCBzf3tr zhG@lz-s0^y6b_fYKt-3WliSpn2cH^Jo-Pl*aA;FDSEieyud3?cq8n96Y-`+5(Tdtu zwJh6!@2J&`(8$l2w(;6l6oscrRB!y$vcDKYG5GdnNN|A=ar5j_Pn)!wrYcj~j1gjx z7A#O*Y!*=}`rREdPL?2=>m=L7_@DiGJ_>GLu;1#6@eI@!#2qS)i)7$I}AP5)T5J%)cY2~A0^Ox zOD?o2{nW-Pn45(UR4UQ=B^m6P{^T^P;-vqZG?TnViS}XN%3Fl);j^`1)1gHd=@{S5 za3y$NU@PvPGpXhdyE%mvZOe>QG0g+1Lw#!2I)-NTCu`q| zqbkCKXM0+50uH2Ic9$M0h0EVum`yEz!#;DG6+s&k9vqr+bi`uHu-;gt>u1}4#Y`7N z8O4Kk^e7=)Dq#G6d^gu6w`|%yI%4)8n`^Ou+ z8Wqp?W!kl$o2N``MKUxzHpp*+dZ~pq8h@Vw!3z*`Tv=*crC}D`CFYYPod&2;pLoYyW->TVcI3) z*|-F>qch*?Cf*j(Y2Jungx9m_R)ZuHyGMXhVd{bNkaA2i@P2fh{Hk6Qszj2?hNkff zaL3)<7bo_AAMqb5#>gk4vyo7?GVzgyj!D#Thw*B!@?w~vuqRyvEd`XsSf-XuSIrDw zM2*;~L-bcNN6}-dfV->qIG4$WIqbrk{o^ zwvqKANh@dIg#r+9LWHlnZe|M8T881(Ic}NWEgF`a}bmu zoruH@mBQDoTQYZ6hqG|)vii(U17p**Z^73Lt={v<$a#y;VmUT_HMP^;eu>L?uevZs<20)31L6sk&(Rm&*r3q=7=l@$C@#LC@sK+$U z@q5QSTIExz2UA;50H15)B>z8O#9R!^*~+mlCs|qQeAGzP#Kh3iQXz5cP2Gz#y>?SS zdy8`AnSBj1mtIb0h<}A5T%9Q^ZzzR9ot8~Qa`F7-!h9gMc7Cy2K8tjTc1rU+2XSL0 zyl@M=9)absLtymgZ7oLtg+_>Qbj}_C{ZB}NZF7gh`Wf`+#fWd;YK@Hmq$Etd2nCsM z4mENQa6KngKu0j<18e77(suwVXXd(83r-vp&J)X4y@Q@N5`X>vl^p`A{PGJhn1d)3 zvzf0|S1)`}Mc%uAf9mbo{Zf(4uaJn*;y5?(;zmaY`-*(^?HsWj|M<5>61aY}9$ynQ zD3LUe^@#l^)dEN7aeM=@V&!MTfPq{6BLl9%@P z!D=}Sb)anF1s3Kqe-9p@GZMr6?z0KUa6tbbZP#O)(&OstnpqoA0;!EF_+1G)a0_O9 z^5j*g!B$D&f|C_$a}zvp6f7PE*0k)>v>QzmqkLM&?3H2yn(Dm1?p^0Al2S-7`9tR| zSetOX(zD9$-rhZ2AeXHGY+Q4z@T%cIT}I{R<_<^eg_sdhUxYEMsUkr?_tscM{J(tp zLTnt1Go{+z|0mAfyuG6|Ul7pw@es?)_lX$hGJWb1b+MbUT7&+<-iA{v&KuyNub*D} zLAdL1!`*zYT|Exc@lovTnGvs=`j>X2F4;0VAjd_u{ZoD#xgg6$qQpf~bNAAw%Dbus zI@sy~w<{C4IxTVJ0gGs zdUPA^QGWQb-5I=DbX$LV@9Q5nY4I=Y7dz1u1A0a4gzrb@nLzuc;ZZ=5n=MwS?EWe} z`JSrf@i$K!jGO>0#z#ECbS1<1jtSwFd?K(+wfH|r-a|0t4#wFF-zjY3$(q^}7xBIE z%aYTJdJmSZLvadf?!aI#W49jS*sVsGksj^X;Q^H@1d?bjyr%n}{@zz=!kc3%6rX;6 z0io@>&sUX8l}C_md_24-ub`m2)ux-AE~uE9LC`KQAH@G7KX4&vCSk#ni$l3W;XiL+ z1u7EEdZXfQl0fMQ>4cK*7@y#UUcdkB5A)5>I{xBz_vY`N09_u5inIYGc#Y&4KYbdS zPjU$kcv%P8*M=5SQEPKPL;nB;8 z>Vr%^`njU!@Tl^a3!=o<@lZL||B2l_obd(w3ot@)scuECmfPFwcfP)^xcmbw+6y>A zNKo|*a&nP`$BXkHq@!XfJsFoYst27TRPzs-LqgIGd?`4T0iy`T!OP`OR=60fe2q$jB2ygI+-VuEo{3+ryBTqsE@BzTk2Tfk6Pu%b!#sTox zZQyIC?6nK*vAg1|dh-(_gFKG^KJ&0@94^0Uiht6moPY4LeVEEfqW&I#!H0M~E?&v& zO?EqxeDR?bElfo?;4Lqzl=J&F&kL{=akfWrX2R*y{JZpz0-6fx0h@u?XuklQ028Lu z6C~2$wva;K@C^$`Yfy!@FPa=bppuD7X=x#{M5#UxR9aFC8ivww!9TJQ3a{Av`YlmDzT~&Te~_7!qCXIi z^2WV^{#5^zAxb%Wqr1fe^6xO6ve!@V0;l;Y!u`Ti>@G~qPtx@(ZMDc(oYl=&vf9ZLpno=3O$~*x5pN64(sdotf%Ue<9yz30=6Ew0F7Iy$B^RPAjdI`22v%HsdWx zrD=OYw!G0*(-Y>lo=!aLbGNMvBhoz1h%iw>roE-cUt_s*HExMt7KAPkKE8gX{|UuA z{|6Q~-Kad7vMY{Ad)po51^*<_=`X$MjTgx3?$z(TQ)Y)OEB#Bv3<`&Y%D8c=3xO zQFz1o;Q4Vuq4;cv)-~udYzsJl;B@ONu_e7)=C2kolm0DxzhY`$Fj-an!sXAlR8+o< zXBn=SDi;aTaD#3Tx|2Dc5-inSZ*bC0iJ*6s7?0sql^6Tbml!s!7$S|!p3rgV%9DD- zeL!PDMmmN=x<6k#sQouqfIb(0YTxVu3!#!?r9Kt2mPQm{5c+( z$!%9E8mBiI{N(dn@J4QZ_pX(K^0T>r^Kl5(v$-_PfxoF?@i~on;!hHyo%n4%oevg$ zDPx2~L*HAmL!*OzWbI~y02Tx;L530t>VVq4y>67l_-Qf=1$3QhstS~zI2DilTYI4f zu$Oj_I^i{(QxyyPuSqY;V4_XUQu{Z3Kbo^zx39>#Vs=I_%RV$sM>zM93KX<~)kfa9 z;&DF1M_gXW$jFH8nZ879^779NP?kK5oqJ17IcQQSF2BTW4^sLC;}_*!q+qY5=sax< zSprs7Va%_SJ2OGxpuG3hj)qWp73^d4DFW(T=gz(7GO=YZp6UCRWGyVKYQ{3FHr|i3 z95aph+-k(9PSu_u*tOpmseyP&g6Az2x}yu-RXcDuK;*&AD-QzdXLl>yWxU?~s>FI7 zk2{rkfA9L^>0n!_2<`bLy}k;9BaFFXa8eUG34@h62aCP_p~H-w3IxJ?=6RM1A}-lk zrKC2uhJWy&NK?|nk!bFh276-^HQb84?(D|GeX`3#(V{f1Hmu;^v&|r_`q47_3L}C zHt*g?r-L>3|6|6xb24sv{69vhOL9I!VQLUf*`&`U@cn$=m5$Hr6ghwt!26d^5jfBT z2%kUu1;J-<)IU9I{gUroUN8OMoCmTqL-fXCTY&zPK624_vz@sym`?2b^I2vug!Zuh z(uebW(wC1rQ0C^sbEDFU#pVt`OTYc^5MkK4XJFuj|0`A)<*ofkz`wH0xwOVC5DqnC zNxX9v1dnq;B;Pc=`ki05+-0lUdazh!P(P?~Ga|IY1aIcS8M$Nt+y{$Mo=c*mwZj%R ze2@3uEM++hxpHICZwGo^-+SI$$=IH6#u>1oN=i7+8Ro+V+~@Fq;IZ7A>p{3$9Bc7k zN5QTl&+=&guY`~t*Ul3Fo5A%2c@;23WfBB1*21-U znWTU4xcsBgMcMZ5kmpE)R|j>p4z_`9aI&tX#VeP+Qm`J{2T%;)u^I1QH1Gn0CK6&| zgp*CoVNZj7q`E23UTgUq)OB4Lp>dii##=cK*g2ZXiDrjeMewERyKa4%l`g%lkJTM! zow&FfyRK1UT+g1qK9NsczCfHjXIhx@^ZS+B6)E<(qn8-RxgZ`TSNPXF`k4s6>`Bo% z16+k9h=u-ueXmVTO+oO#C?E=w5q0$#V2?NH>fVA}1_Z-%-E|wj=M5_pPJERRj>)zg zKNZqO^RQ33&m43Xc{&)BP?%9cy}dN&xmc@W<7%5n!m~Oc7K*qf;lg+;-Pb;Zv3W%xR14|p&gJ@1bdm&S z$IP^}^<#W#lwZ^)Pc=GvzbyWQ{I`S282*a~P%L;^b<+k07BdD;j_5i+PE>m1=9%_~ zi-^ERo^&YY9%EdU4+V1jdw&tBeLKxjI(e*Y_3SP-(i3Xc5y4pQIed5_ZS~feA8W36 zWGQH2NJ`KA1tCN^c=4HFGx8-=ewR}NmPHbK!m(}0> zYl9WG2K16XpbBto&sW)drzV@fp+>%gL)GdbliY0TCuK-ybm*5z8cFhP>{B{30pz>( zcq(zTKwnx9;zg|iXX=IT`*5@X|6F(Nm8d~>=dpYIJOAhb_+#hH;wBtEfSM&LRMm~= zNp+KSp}jjb=d5IRv5`)PUJUFK5wI>>X3PDIJDjivW$f;L+~+X4Wv{lOl1I?;Q6ecD zC3y1CUZ66u7Dg9+7J39~)uDkCE@2gs#NvXEkkIFlkdUx%-|no**VF$TFE9jY98h|` z{EOCLJCug=5TfHZ7K{}&t&98R`08A)ZXNN z(A9e&yB&cc>Gw4D7lal3WB!A`PA_*By2Gt! z3eDQA?z0=pji-BBlyy?m(UYn zte{{bB6R!S#M(eznKg8IufF!;U*m0*sX<>$i#OWIi&C@qVfgqLOvncg#l?Yr`UeO- znp4LRp;jJ?Ts^dLmr&5g&-qD_7M877It>)TU^?d?D`AL! z@T?`gBP<-e!aZ&1|5YRff)RE%7tE)zZ{`z6-Ns3;UCx_NW)c?<)r^i#)e;dLx4xlS zJ&;J}{_OG@Vz}v1Kz3q_Q0)r{?jY1|KmJtvM;{t(ne#xW8u#eJsF4|O8X=Jo&;X!WJjc|!1h%f$2-8(cI9dH=j@dcxMgCYUC^tbKi z0jc}TBH7#!J-#Y2R>yt&76D%6K~~Dkd5gGlXKMLsZhm|{llADPr_eeh6(g`q;FV5J zcUDW@oJVcWjiKn+{0U0pcuIgAPYvtK@lhl_{2E*-WR z11VcA9%XZLGjAnbp*8K;etuhh@Wwl*?ZyU+sR82kgQglEpG>m6H=2y~HGEGO(PcXe z&n*srsax!b5#7cdNFQzIWBeO#`H@9{eLsGI{grn9`GWYPesFv;Vv7-ItBQ>qVrw0_ zJXU0+NRg0@@&(ZOv+ry>Ydc@JEtvFC%lM%kY;mK#3T%T+#CiVh&C~W%c9+dc-gWbn zleMXOuwV|@8Et*JsQpcbs^95a{o3Tw>5kkHxwb2DY5u6s;<%P?!0FQ3WV7ph&`!pu z&z_!_IYF?~!E4!^pUdsBAvKI{TQ0A)(Gs{DM)) zqi>$K<}r-`X2)!Y{a`~+C^|iu@~hQ*(aiC+20&&q_0CoWB%AT^Zetc65dq*-ikm4m zz(`uad?W|y?q7g!@c~~}cMpG#)968-* zPNW&j#70UigJjNS(gHS+et7KSDmq?ipZAZN_v;`rc6d@8So%V{*w~|OZ}-?7_fRBx zV!G*?Suo0gocl76kXmvm#gpkJ-}OfFw~EaJquF5nGDr+){A2^fMT5<6^rG*4TH`aM zwC-k;gZGjt{h~HG!JDxk!;Z?t13N7H7=2`V7DGo_ug&qmdYg3j>->J>ELvM5tLdU~ zQqa}HyQ?4yv;-8=Q#2QrG)LNd{CJFl%=FIPanGMW#}{-Vme*RdV1Tto(!G&;jTsMu zv8=iwmydVPlFww9Z#GLrFh|tJ=)*vpIt?&;Uk1<3AWr& ziKTv4K7J0ULg%l4)nH$4`&AAg(%NFycIYwcsz~msu<{5>@h}7plmtZH#qvK7p{h5{ zU}X%5--JHo(eow+zKwaei!H#clvq5ZSQB?S3P_D!G65L18`0UzoAIC@54>J1aR@HO z$z-g^10EB4*xuf2#H*JyueqBosro_iF!@=uqw>^L5M#rr-fd$b@!2*#=DwwEtP$b) zLw1Jmc@;1Wrl;a~;iE0HOq?TU8`)sJs`}yW-<5Mu$4=i~19J24*Sn?x55E%`6*5Lvcd;zLr#U;wf$b0OZavo@|r~btMJU#^^^T!A@C3#T7)XW8@X%l zQ3hCL{yqi!w9vvdxwVNHIXbG|Tdr4{dpA?yG^;X3m}EB_uv10&gSv_D zE0&L+*6?QYwADj@&2MOq%Nd)sqyCW%h{#{ zN^;Vn_wWBNNvl6tG(nb8ZLr5;b>!VR^MX1zAq&m+_ckmE=PU@ z7Q6^%RFA&50^9rcUcGC6^i(OLgfXSYj!NKo&+pSuxjH~e?f@je7=n5_@em-QuAZ+l z;4Gh3C0ONjchWD&DdL(bsI+0{0-QXnF+c;JxQ)`C3DaiOmZpUo3s45|Hj}}PBB>xw zg-~{`?G7_~5@C%HHjLN>H!%y@$BTk1OWQ->iVl`MS>uQcAIX|C#sjUMm%8-+{K4|H ziR)yjoNMcgYD7*A*g_O_N(#u0#Ym}z4neN&-73I(1^^8x!@UUc*52U1Rf6Y@#r z{%8iR(BBjNCwwP^->;6;#v#R-w8xU9eh4{ zU~kNNKz~({pZQ&sGP>7^faG*2FVzBK9d%eQaSTO}4;^W6t$_^3P0nHtx*BxNeLtyn z{jUI&nEHokJ_CwI27GTJy>aDDwXnJJ;CASOC*(a7FTar^Jmk#)gOZc73iuXN#G zjpZSw0}kM1S*m)5s>%8AX|jKB=_!4n*>=~T6b=8(nsS2DK3g^Lyjp9(bKm4UIPICq z)UgmUuZ2GN7bh zhnes-9Bvx%!-sHxB<~y*)GIp7M(GbRf(8SgnwM+4g`k)tb>qoD6XuO_XPm!r_hA>o z!zG8I&k)_lv4)tJ*GZ###W3vj9oD~z2#AGz3YB1NxwxO)S+!U(w` zR@RaM`{EJU|JvH_8QcMNfGx1w-LJde?Ss0->Q&U`Ky9dx-}Gs9^;243;T6 z&#?oc=vmtSg7NpqQo+Z7eSi;Oo^3dr@ttZV-iC;Yt%)frS6VMQ9!0Jy7d6b{A3%iG42ijz6 z-x5hMMxCF_v@o#m82Z!PO78&XkZ^yl*Lb}$Xv}Y1OPhS^4R}I);J=6x)4(r`koR^2 z=p9y5ls&)mw{faKFetNc^_LnuD#RsG!(Z6X&tiH0$KJ|ze#1x5w_64$co3?-;QHr` zqW#B08Qov`$mhBTK@U=XcbD;&%Jv5x*O!)bBfFjU(0hJ%%A#_VfRkc?zmSh$`Fs0p zJkMB@p^=L3HB%0gTsNiX293b%LNG29Va@)Z+Rw&5a`^`Y1Q>Uv_mnYJ#M;^iHcq3q zU%?1lz~+c@a5x|`9*`S6XK&3DcP6u6YPZ}H94Ep*O$8`ed>GdwvgrwKNSX`!)wJIG zX?vN|Vx}l)vWRKTTR#*aD2ux%EJ6QeNg#Hbf_>^?wLZlJFs3-Jhig>@_YNoDIa$p( zX_PrJn2o9jJu9R}BB%Bw^(VI$gH@cD5`K5p>`v7++j-W48~?DMODFL`%xyvZH+Kzr z1~XoRv3}>zU0yAm5&SCXY)Z8QAOH1x*M-P+b75xhVC-P`g8BVw$I?kZ%<*HF{V{!u zBHF1xgQZi;6FC9$fJh>xe)PYH@>2U98%SaR(ZNI#Jz;z0D#xL{0||ou#^kPqbLN64 zdd&cC5SWu-?vuMZF_6{2&xz-MAnB+<1B6?7a9mS+!zB@t2rcl7Scmcbh9fzQi8Sbb z``q1e4d3?sQ;ogDjP+Gwy1RCLlPBBlQyXzUT*Z%=7}iX)!1zoS&vm24lb*HJFxn*W z3mN1|fnL?(t=Pjf=*hpP`IK25i;M*MP;2>UAN8;O%JLW=$LHFUh;=lk>JxAj6gb#$ zc|8(D%!vu``K_X*HLzp}4YK<@AC9!ghG#kaH;_!5CuqP!cD{jxvDUgtwBXl9l+}7$ zR<1UDl#3iwW6j%C=)?CEwe3CboMgvaQx^QY+;05qa^3BzE}(1+zr#Nrwh&t^?s!}5 zo84d9&Gzx3en{~2z4I;=5VV!J{?r&Y68lh!gO$VDH^oAJ**7bs1KR)z63CJvulf%k zlupJE7xi*T1quAT1Ao;#uW_L9l`Ks`)i`$5Xi!rmKfGIA=6sS;_HnO$YB?sqK3Ci2 zQE3~79Md!wz}ZF;V2n9oAt0z3HsM(6HERN>bGAoMG^I$ofvJ77!S+Z`l>nsg@WFoR zP>@6s6BC2Mr!I^oJOwRlyNBU0r_*Nb1}1av?6$@2aRmPAYLcMW zIC$De;pf4GA=2L&|LRBXLQopxjY4}V2uQ)EnT{m7qM9nH2l9u^Gj z7L{qB^UnWmzLxVVO2PhURe7ype^`*;n~v9sM~0vLu5tgA-*9Cv_+%sU`Oop{0{gMG z**|l+AeRHt{*c8JxcQq`Jg9w>u_$ujCn4FWW?;m)JwxE>o=>9X3j(t-pBtEC9>#bK z!SgWzvghMYysIvI@0_-j`%?_b?w>GL&McpU=whW`|v3}=z1V1PSxpEIt?KZf6+?o0G&O&>6c-KP^LH0Yzm5zt=WNlCR zv^`*t^S1%{(E!}AmBlg=6!KBs?=$#Qme303Lok5l$`PwM)o0#3JrruNN9$4^!h z8uCwnkIt`sPX;?c10O_jOamC(2;jxag`Jmj_(A+@cDx|NrEdoL;5GM*x7}>Pl#Q>w zYo)vQOjbH%T=Svk-{_f`f}A*ud!uAK+152F%FP@t{%Ju_sn!X=go1*CPFo_@Y>;@wpDtg^ z&|KO*l+zZ-|A$@+lJ{R^``32e~wp5v+;_gTZy(+`r#2LWgq zWD9QB&uSE2W|+>iJPsIv3Hc^p!T>A6zA)V|_6NW&9V`$IV7?E+Mu*`qP%#KYl+X2( z_H)-Q2eis9w^>6F$s1eAxL)BZs-G_+U{2LssPt1`B%^XvJV#H2cfw` z)UNT3Vxh|bF^&!hkI$}MwR;8)oP0^aG=8`69li6UP?Hx3MqYRJi5R z?uJ5PA4qudY%n2|Q7DX(IhJ1itqO8-2{|up>AVKc>c9LT(xAxxDu_aVMfEJ$ z3WM8+74SXXoV?hib+O|n7@>kjR8Mc?F>4PvtN^N*oeS1Oj2?Hf3B%txEMv-9Zj2@( zRB>7D9=C5oPLPH036@9~Yzov8XSi}jy4yOvoptPnD)PF!e##h2Vc^UX4V@w@% zp>;+KN8>9UP!(9Qh3a^cQR1OTV?|b25pAAT6syH=;uO*QnU(U&v9~5uia%Se*53u- z0eEn1(qw?mc^|uwUrIMT98OK9PG5AIG%Ou7>R`Bo2`#!+&IQS zX%0r1R&b?u`=Gk)SeoF5Uwgxe^WEM$bSB4c$Dk1XYBR;6cR`8PZ(&Dc(8p(hy^dW3 z7c0mP(ZEGa@2iyR^LbV~tpO~i(-Sf?Gc!@fWV!dy_3m1H&g3N1X$F_;TBmlsc9kQ` zq}^J>>E5uqZuJS+)qC=X$5q{G;8U1m08Vtl2qMv;P~Fm>H2&?B)7rZb{>>Iv(+EJ{ z@@LT&(0$3b^F-b}b?MPQ-+uk}7?4^mmwgKf(4Oms^nO6S#6yB}`k|V>g3wz~Rj4h- zPHiy}j!r+525CNU8`hPYbH_4Kt$-PKg|T}TceI4p&@;h1#8Fa*&XIsY8L$ZGUH z%xxERUu$N(;d$hu$v5586_{U-F~m3e){9#s#c&R=c12r##H!2KMSa!52Ju15l{&o zs*3!(T2Bnq_nvBrq6qHioSO7h?>zePuzzaNlWyHK%woA^fs3n82sG5$f{Gb{h0JpG zk6?nO2NERX55ZG}G&EgXZv6kMyY_#m^Zh?Z+wR6bT$T(i=0q2jjLi|t#IDFjakRA( z#;6@q?bNuA$oOujMT6P4gUYRCQ=40(m~j~+%-BprB_V{F5N2qM+hELjeLmXrIRC>K2UF9lc()jU7#*s zUJx_u==O7B;dEV+UwgfY(CilMDoHciG4HR814g2iq?5n;&BC;5H<7k*GM6`RbCPOD ze2$!r(fIE+1>tJpX|$Yew4bIibOkHv>Qd`iFaP>wazf{18Witqxk3t ztq1RIS_K!r^)(dYd7E~T-CiILl~#aJ zti?0h>CTwMDYyE{+C|j_gZfU%zq@lxX&WZKQo>8GU{k(;NhGCa7KcaG4SewIM-Va| z2TU+w@}`@%)GbVoLW!4D;0NOGPdhJeryHuJOlIrNE-m>SIj9jDAF9}L&@5U*3n|Fx z*;TY}9c}z*{l$dfmgci^W#(Nix`p`^k)s=YERLX_DWN_x3Ma!|55^F@##Ay0^Kj+}!-!lzRf;@(Hq zM?f#HyBz4`F-gvJP>pW4*#Q$rm1q4uEpRrHjKOUD#V}7fdg~kA>uI5O^B$)5cw$O` z$U18xh}nU^q#qq;(SK?s3v|huCx3LNfUudaS5- zq#vmGnCsgS$=os?<#=t&LCE>6t@y|3P^gIW!>?F-*T?PAE-Ot7eKO%4SWnxJ)NVCC zeWD(>4!;J%|^?A9JcrQ~Uu2L>d;Lz+0oi>(BnL^W`f@&Lj;! z^a4wpv|}qe%vPx`EDNbElWgpt1;`TIuD`Y30SzV!CEt|wPu$qt@M$FeYzR(r7%zLp?L??#F2E?=JE3#B!c}*k~XTK;ev?KD4I*dj3RhE*w@1Y+Cz8Id>87u^lWu-k?0t_~w65{zsOFJ3&R&Hi3)&^I9j~ptT^)j9_MW9>58guora# zGYr-X-@?kwbV#7l;gl%1o0-=z}KyxJSd$?)WvJjH_B~`}*;*BOJxu+}5uU4k<@2FUK zX3D)&ve7OMZP+!CTV+<1@so~;gRYJl!AO1|re@=Gs~D9LxZV zsa^}c*j4L9#qi+jqs#U}^IO|>Vy(6Fud>_o(lclJI5Q^|86M8H5&4y6Q5i4Dd4?%;Hb-aO9AbLHZbYuw(5Qj?|UAO9Yh(fkRUHOs||i#jN7 zRdhR|Q`Mt7zSU&epli5Eon)e2Oci^C@fR(|4_^6jE@M5PGsSZWRw z@9zC9alITy6(da;%QDT7>{>2tkozZ8xqD0x2yrdygfW^)fd5r#d){#e#rGz?^gVAx zkjS0Orm8n&hf^-;b-(f!OvsB^@A+7kXfy;UlaL@4R#KJ7lN}j_Y6gf4(uSbV{I>R3 zU9VlN`ihJ`drAwFxvJWKxS!c9pBe9@o+0mRr!VGksts8*X&G(7huyg$!HLqJV5FS! zw2J?8BTzn(ITmMdCGwVF2VzKGD1|Wa3@K-wL%?esgJotvMKM*c9*;zJSCv9rD04`Z zrqdLegoeQ5sUxG_3DF~-3CbIDQ*Rou)QBBfSc~$(zHmMeZnT6aXh54*EJQ7Q)B|O3 z%-T{|_LwuRe|z5~c6|#_QkiThXPRz|;|{jGmhX9`otN6p#2;vpJ0yx}CKso<4)g^b z9|K}=0CQ*7$&k(FsG@yVE3)oFqBrsc6oSO%Yk|ZiUF(sX{8stYyfC%+&9KJ8w0rby z)pYaV^hol_xtGHQ4b^`XWe_6JQ#(l~QETFNp=LiQadux9l0Zv)nXzuDc&XgWzK^Oy zb@O)~&B3vWSsrG3PNG`~v&cbHg5@MRuYU{(y^Xh%b`q}KPmiU`&~geICI+g+Ik+pe zXQ{HbvV!``9=0x-kTy4$M+Dj!Bkbn)@YKiWdEVRe<3^290^d7L4ax@UuxD8&$yrxZ z>bRz5)ajXIIWc;hH_pXCYmUoFRJsN>bgjINPR`0UpQxj@DuLB8HrIgdq3Yn+F+LL9 z=cWQ8RAh@(CCoRq$KqlsEqQ0`GE4$8q{0fxU6w3nRy@_kOJ|l-=5AePMbLs<^1P_= zVOY2UGykoB79>*&!$;%wdA;%+1Z9A)BSTv)ZWq-UcT>LiEiV;#viOtv@m~@HeiTF5 zE&tAh+sYFypRa6}hEg4BUBvBk72?$l#(IRFr>{Ze7YPtW!@jfo^7`l?<+p?CZn(T; zOlI@0Cbwp^-n{NbRn167ZSj2Jd7fTL@=S_kP~A0gvR?(NaH6_hv0Kcy-F}LG$=11M z=PHm*3I~?~L6s2RpLc^wp0S!|kPSRN(C(CEQCJhb+4_<`_1)862YLS~;xD^fukCkf zyP??6intIziN)up`!O@Y*KgXp?i7rXbOeeIkb;aof}MvuLEpiyB9AlZhxq;NLW_zs zGd{w(Ue?lU@6CU~b(oJ93n9+J6kAAuNL+TJmC3{8L-`e(&Z`C(b@ z=yb-B>_2b0c(^m@4G~t?=(nKhf8MIYii;G3ZZU7q<;E*cuMBVCu_aC0>Dbu&BDLCv zlDHa9h&eH8}I!Hox%y1&QJYpau^yuZMm|Tt&_@ z*-(5XxL*H!K|gLX_|oUN#98IPMu?i5hd-sbOId^t3k1wwOVwBZ8-+k? zmdQ(Uoo+RGg~#XV)1zkYKr9etvlL6=%a&Es4FqYcVCmv)b*?0^<*|O4q@TWuYjq*g zbc0pXYOfW=-~hw-+y<s0IoWGoP9wmy z5eVCSh1ycP=Xs4FcOSg@q`P~?n8kShW14)ngc=&Xbv|3q*Cp-z^Z+A%;Z@=NTc^z# z5h1|@c9e~_Y!Dmg_EP7(pbH@4CM^5prIwL3$7u#iLoPqQE!zV{EN`FR0|YK9+%6wO z`>tB|6Tghs)S_g`v)}f!9&vQZH$8~mzIK!H_kHoyg((q-DmxKa7wsaj!=P9V=6d+& zt|U|;ctI!&&w3&pb*Ma%hl>uHRz?F#07XjvSu$l6aFl>wR0cnPT>`cMbQqU--lsgf zIQ(s#^&+fU=&z_Zc{&IU8IK;bt3LaC_>$#0FcLS8X^`MXlKGk+4T#40x9_Zk<{gn} z*H~1qHn#K-ve}*E1kIn4n}@%vKw|wN5HnJK50cTx=Q~k(08w<3%{|8^L(%-K8yLlbc R#sL}ZL3eMra#zw%{{i84iI4yQ literal 0 HcmV?d00001 diff --git a/images/vscode_remote_menu.png b/images/vscode_remote_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..2218351c0523ec88d71d6a5550abf4fb2a36cb97 GIT binary patch literal 51685 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 literal 0 HcmV?d00001 From 3e55b9e6c21aab1ed2cb03338475b293605b5cd7 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 16:58:44 +0200 Subject: [PATCH 20/44] updated build.rb with new partials --- build.rb | 79 ++++++++++++++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/build.rb b/build.rb index 01d8f9b..c42954b 100755 --- a/build.rb +++ b/build.rb @@ -15,30 +15,27 @@ setup/macos_slack setup/slack_settings setup/github - ssh_key + chrome gcp_setup - virtual_machine + homebrew osx_vscode vscode_remote_ssh - vscode_extensions - cli_tools - setup/oh_my_zsh + gcp_cli_setup + gcloud_oauth + terraform + terraform_vm + vscode_ssh_connection + gcp_adc_auth + gcp_cli_oauth + ubuntu_ansible_part1 setup/gh_cli - ubuntu_gcloud - gcp_setup_linux dotfiles dotfiles_new_student dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop - zsh_default_terminal - setup/ssh_agent - ubuntu_docker - kubernetes - terraform - ubuntu_spark - ubuntu_python - repo_overview + ubuntu_ansible_part2 + ubuntu_vm_test dbeaver setup/kitt ].freeze @@ -54,30 +51,26 @@ setup/windows_slack setup/slack_settings setup/github - ssh_key + chrome gcp_setup - virtual_machine win_vscode vscode_remote_ssh - vscode_extensions - cli_tools - setup/oh_my_zsh + gcp_cli_setup + gcloud_oauth + terraform + terraform_vm + vscode_ssh_connection + gcp_adc_auth + gcp_cli_oauth + ubuntu_ansible_part1 setup/gh_cli - ubuntu_gcloud - gcp_setup_linux dotfiles dotfiles_new_student dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop - zsh_default_terminal - setup/ssh_agent - ubuntu_docker - kubernetes - terraform - ubuntu_spark - ubuntu_python - repo_overview + ubuntu_ansible_part2 + ubuntu_vm_test dbeaver setup/kitt ].freeze @@ -93,30 +86,26 @@ setup/ubuntu_slack setup/slack_settings setup/github - ssh_key + chrome gcp_setup - virtual_machine setup/ubuntu_vscode vscode_remote_ssh - vscode_extensions - cli_tools - setup/oh_my_zsh + gcp_cli_setup + gcloud_oauth + terraform + terraform_vm + vscode_ssh_connection + gcp_adc_auth + gcp_cli_oauth + ubuntu_ansible_part1 setup/gh_cli - ubuntu_gcloud - gcp_setup_linux dotfiles dotfiles_new_student dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop - zsh_default_terminal - setup/ssh_agent - ubuntu_docker - kubernetes - terraform - ubuntu_spark - ubuntu_python - repo_overview + ubuntu_ansible_part2 + ubuntu_vm_test dbeaver setup/kitt ] From 136f0d4f733f05a2486e160dd7d32a5a4f003d24 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 17:00:25 +0200 Subject: [PATCH 21/44] corrected typo in build.rb --- build.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.rb b/build.rb index c42954b..fd269b3 100755 --- a/build.rb +++ b/build.rb @@ -21,7 +21,7 @@ osx_vscode vscode_remote_ssh gcp_cli_setup - gcloud_oauth + gcp_cli_oauth terraform terraform_vm vscode_ssh_connection @@ -56,7 +56,7 @@ win_vscode vscode_remote_ssh gcp_cli_setup - gcloud_oauth + gcp_cli_oauth terraform terraform_vm vscode_ssh_connection @@ -91,7 +91,7 @@ setup/ubuntu_vscode vscode_remote_ssh gcp_cli_setup - gcloud_oauth + gcp_cli_oauth terraform terraform_vm vscode_ssh_connection From d61fc91cb410c2b78bd4be118c9bae5fa73df19a Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 17:02:28 +0200 Subject: [PATCH 22/44] added back_partials/python_checkup.md --- _partials/python_checkup.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 _partials/python_checkup.md diff --git a/_partials/python_checkup.md b/_partials/python_checkup.md new file mode 100644 index 0000000..363c219 --- /dev/null +++ b/_partials/python_checkup.md @@ -0,0 +1,31 @@ +### Python setup check up + +Check your Python version with the following commands: +```bash +zsh -c "$(curl -fsSL )" +``` + +Run the following command to check if you successfully installed the required packages: +```bash +zsh -c "$(curl -fsSL )" +``` + +Now run the following command to check if you can load these packages: +```bash +python -c "$(curl -fsSL )" +``` + +Make sure you can run Jupyter: + +```bash +jupyter notebook +``` + +And open a `Python 3` notebook. + +Make sure that you are running the correct python version in the notebook. Open a cell and run : +``` python +import sys; sys.version +``` + +Here you have it! A complete python virtual env with all the third-party packages you'll need for the whole bootcamp. From 49961bfdf9f62b1274bb29079dd4e4d1d5f256d3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 15:02:49 +0000 Subject: [PATCH 23/44] setup guides generated --- LINUX.md | 1195 ++++++++++++++++++++++----------------------------- WINDOWS.md | 1153 +++++++++++++++++++++---------------------------- macOS.md | 1207 +++++++++++++++++++++++----------------------------- 3 files changed, 1523 insertions(+), 2032 deletions(-) diff --git a/LINUX.md b/LINUX.md index 299bf83..d60679c 100644 --- a/LINUX.md +++ b/LINUX.md @@ -6,6 +6,42 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: +This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! +- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! + +## Part 1: Setup your local computer + +In this section you'll setup your local computer and create some accounts. It will include things like: +1. Install some communication tools: Zoom, Slack +2. Create some accounts: Github, Google Cloud Platform (GCP) +3. Install Visual Studio Code (VS Code) +4. Install and authentication the GCP command line tool: `gcloud`. +5. Install **terraform** on your local computer. +6. Create your virtual machine with **terraform** and connect to it with **VS Code**! + +## Part 2: Configure your Virtual Machine Part 1 + +All parts of this section happen on your virtual machine. + +This section includes: +1. Authenticate your virtual machine with `gcloud` +2. Download and run an **ansible** playbook to partially configure your virtual machine. +3. Login to the Github command line tool on your virtual machine +4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! + +## Part 3: Configure your Virtual Machine Part 2 + +All parts of this section happen on your virtual machine. + +In this section you will: +1. Download and run a second **ansible** playbook for some more fine tuning. +2. Test your set up to make sure that everything has installed correctly. +3. Create some python environments. + + +Don't worry, we'll go into more detail in each of the individual sections. + Let's start :rocket: @@ -89,62 +125,15 @@ Have you signed up to GitHub? If not, [do it right away](https://github.com/join :point_right: **[Enable Two-Factor Authentication (2FA)](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication#configuring-two-factor-authentication-using-text-messages)**. GitHub will send you text messages with a code when you try to log in. This is important for security and also will soon be required in order to contribute code on GitHub. -## SSH key - -We want to safely communicate with your virtual machine using [SSH protocol](https://en.wikipedia.org/wiki/Secure_Shell). We need to generate a SSH key to authenticate. +## Chrome - your browser -- Open your terminal +Install the Google Chrome browser if you haven't got it already and set it as a __default browser__. -
- ๐Ÿ’ก Windows tip - -We highly recommend installing [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=fr-fr&gl=FR) from the Windows Store (installed on Windows 11 by default) to perform this operation -
+Follow the steps for your system from this link :point_right: [Install Google Chrome](https://support.google.com/chrome/answer/95346?co=GENIE.Platform%3DDesktop&hl=en-GB) -- Create a SSH key +__Why Chrome?__ -
- Windows - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen.exe -t ed25519 -C "your_email@example.com" -``` -
- -
- MacOS & Linux - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -C "your_email@example.com" -``` -
- - -You should get the following message: `> Generating public/private algorithm key pair.` -- When you are prompted `> Enter a file in which to save the key`, press Enter -- You should be asked to `Enter a passphrase` - this is optional if you want additional security. To continue without a passphrase press enter without typing anything when asked to enter a passphrase. - -โ„น๏ธ Don't worry if nothing prompt when you type, that is perfectly normal for security reasons. - -- You should be asked to `Enter same passphrase again`, do it. - -**โ—๏ธ You must remember this passphrase.** - -
- โ—๏ธ /home/your_username/.ssh/id_ed25519 already exists. -If you receive this message, you may already have an SSH Key with the same name (if you are a Le Wagon Alumni or are using SSH Authentication with Github). - -To create a separate SSH key to exclusively use for this bootcamp use the following: - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -f ~/.ssh/de-bootcamp -C "your_email@example.com" -``` - -Your new SSH Key will be named `de-bootcamp`. Make sure to remember it for later! -
+We recommend to use it as your default browser as it's most compatible with testing or running your code, as well as working with Google Cloud Platform. Another alternative is Firefox, however we don't recommend using other tools like Opera, Internet Explorer or Safari. ## Google Cloud Platform setup @@ -287,314 +276,426 @@ Go to your project [APIs dashboard](https://console.cloud.google.com/apis/dashbo - Compute Engine is now enabled on your project -## Virtual Machine (VM) +## Visual Studio Code -**๐Ÿ‘Œ Note: Skip to the next section if you already have a VM set up** +### Installation -_Note: The following section requires you already have a [Google Cloud Platform](https://cloud.google.com/) account associated with an active [Billing account](https://console.cloud.google.com/billing)._ +Let's install [Visual Studio Code](https://code.visualstudio.com) text editor. -- Go to console.cloud.google.com > > Compute Engine > VM instances > Create instance -- Name it `lewagon-data-eng-vm-`, replace `` with your own, e.g. `krokrob` -- Region `europe-west1`, choose the closest one among the [available regions](https://cloud.google.com/compute/docs/regions-zones#available) +Copy (`Ctrl` + `C`) the commands below then paste them in your terminal (`Ctrl` + `Shift` + `v`): - gcloud-console-vm-create-instance -- In the section `Machine configuration` under the sub-heading `Machine type` -- Select General purpose > PRESET > e2-standard-4 +```bash +wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg +``` - gcloud-console-vm-e2-standard4 -- Boot disk > Change - - Operating system > Ubuntu - - Version > Ubuntu 22.04 LTS x86/64 - - Boot disk type > Balanced persistent disk - - Size > upgrade to 150GB +```bash +sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/ +``` - gcloud-console-vm-ubunt -- Open `Networking, Disks, ...` under `Advanced options` -- Open `Networking` +```bash +sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' +``` - gcloud-console-vm-networking -- Go to `Network interfaces` and click on `default default (...)` with a downward arrow on the right. +```bash +rm -f packages.microsoft.gpg +``` - gcloud-console-vm-network-interfaces -- This opened a box `Edit network interface` -- Go to the dropdown `External IPv4 address`, click on it, click on `RESERVE STATIC EXTERNAL IP ADDRESS` +```bash +sudo apt update +``` - gcloud-console-vm-create-static-ip -- Give it a name, like "lewagon-data-eng-vm-ip-" (replace `` with your own) and description "Le Wagon - Data Engineering VM IP". This will take a few seconds. +```bash +sudo apt install -y code +``` - gcloud-console-reserve-static-ip +These commands will ask for your password: type it in. -- You will now have a public IP associated with your account, and later to your VM instance. Click on `Done` at the bottom of the section `Edit network interface` you were in. +:warning: When you type your password, nothing will show up on the screen, **that's normal**. This is a security feature to mask not only your password as a whole but also its length. Just type in your password and when you're done, press `Enter`. - gcloud-console-new-external-ip +### Launching from the terminal -### Public SSH key -- Open the `Security` section +Now let's launch VS Code from **the terminal**: - gcloud-console-vm-security -- Open the `Manage access` subsection +```bash +code +``` - gcloud-console-manage-access -- Go to `Add manually generated SSH keys` and click `Add item` +:heavy_check_mark: If a VS Code window has just opened, you're good to go :+1: - gcloud-console-add-manual-ssh-key -- In your terminal display your public SSH key: - - Windows: navigate to where you created your SSH key and open `id_ed25519.pub` +:x: Otherwise, please **contact a teacher** - - Mac/Linux users can use: - ```bash - cat ~/.ssh/id_ed25519.pub - # OR cat ~/.ssh/de-bootcamp.pub if you created a unique key - ``` -- Copy your public SSH key and paste it: - gcloud-console-add-ssh-key-pub -- On the right hand side you should see +### VS Code Remote SSH Extension - gcloud-console-vm-price-month -- You should be good to go and click `CREATE` at the bottom +We need to connect VS Code to a virtual machine in the cloud so you will only work on that machine during the bootcamp. A pretty useful [**Remote SSH Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) is available on the VS Code Marketplace. - gcloud-console-vm-create -- It will take a few minutes for your virtual machine (VM) to be created. Your instance will show up like below when ready, with a green circled tick, named `lewagon-data-eng-vm-krokrob` (`krokrob` being replaced by your GitHub username). +- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Extensions: Install Extensions` - gcloud-console-vm-instance-running -- Click on your instance +VSCode extensions - Search - Remote - gcloud-console-vm-running -- Go down to the section `SSH keys`, and write down your username (you need it for the next section) +- Install the extension - gcloud-console-vm-username +VS Code extensions - Remote - Details -Congrats, your virtual machine is up and running, it is time to connect it with VS Code! +That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. -## Visual Studio Code +## Google Cloud CLI -### Installation +The `gcloud` Command Line Interface (CLI) is used to communicate with Google Cloud Platform services through your terminal. -Let's install [Visual Studio Code](https://code.visualstudio.com) text editor. +### Install gcloud -Copy (`Ctrl` + `C`) the commands below then paste them in your terminal (`Ctrl` + `Shift` + `v`): +Add the `APT` repository and install with: ```bash -wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg +echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +sudo apt-get install apt-transport-https ca-certificates gnupg +curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - +sudo apt-get update && sudo apt-get install google-cloud-sdk +sudo apt-get install google-cloud-sdk-app-engine-python ``` +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) + +To test your install, run the following in your terminal: + ```bash -sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/ +gcloud --version ``` + +### Authenticate gcloud + +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. + +To authenticate `gcloud`, run: + ```bash -sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' +gcloud auth login ``` +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V + +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. + +To set your project, replace `` with your GCP Project ID and run: + ```bash -rm -f packages.microsoft.gpg +gcloud config set project ``` +To confirm your setup, run: + ```bash -sudo apt update +gcloud config list ``` +You should get an output similar to: + ```bash -sudo apt install -y code +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] ``` -These commands will ask for your password: type it in. -:warning: When you type your password, nothing will show up on the screen, **that's normal**. This is a security feature to mask not only your password as a whole but also its length. Just type in your password and when you're done, press `Enter`. +## Terraform -### Launching from the terminal +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! -Now let's launch VS Code from **the terminal**: +Install some basic requirements +```bash +sudo apt-get update && sudo apt-get install -y gnupg software-properties-common +``` +Terraform is not available to apt by default so we need to make it available! ```bash -code +wget -O- https://apt.releases.hashicorp.com/gpg | \ + gpg --dearmor | \ + sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null ``` -:heavy_check_mark: If a VS Code window has just opened, you're good to go :+1: +```bash +gpg --no-default-keyring \ + --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ + --fingerprint +``` -:x: Otherwise, please **contact a teacher** +```bash +echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ + https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ + sudo tee /etc/apt/sources.list.d/hashicorp.list +``` +Now we can install terraform directly with apt ๐Ÿ‘‡ +```bash +sudo apt update +sudo apt-get install terraform +``` -### VS Code Remote SSH Extension +Verify the installation with: -We need to connect VS Code to a virtual machine in the cloud so you will only work on that machine during the bootcamp. A pretty useful [**Remote SSH Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) is available on the VS Code Marketplace. +```bash +terraform --version +``` -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Extensions: Install Extensions` -VSCode extensions - Search - Remote +## Provisioning your Virtual Machine with Terraform -- Install the extension +We're almost at the point of creating your Virtual Machine. -VS Code extensions - Remote - Details +The specifications of the machine you'll use for the bootcamp are: +- Operation System: Ubuntu 22.04 LTS +- CPU: 4 Virtual CPU cores +- RAM: 16 GB +- Storage: 100 GB +- Network: Static External IP address -That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. +### Cost ๐Ÿ’ธ -### Virtual Machine connection +Creating and running a Virtual Machine on Google Cloud Platform costs money. -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -vscode-connect-to-host +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! -- Click on `Add a new host` -- Type `ssh -i @`, for instance, my username is `somedude`, my private SSH key is located at `~/.ssh/id_rsa` on my local computer, my VM has a public IP of `34.77.50.76`: I'll type `ssh -i ~/.ssh/id_rsa somedude@34.77.50.76` +You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. + +### Download terraform files + +We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. + +First we'll create a folder and download the terraform files with: + +```bash +mkdir -p ~/code/wagon-de-bootcamp +curl -L -o ~/wagon-de-bootcamp/main.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o ~/wagon-de-bootcamp/provider.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o ~/wagon-de-bootcamp/variables.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o ~/wagon-de-bootcamp/terraform.tfvars https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` -vscode-ssh-connection-command +### Set variables -- When prompted to `Select SSH configuration file to update`, pick the one in your home directory, under the `.ssh` folder, `~/.ssh/config` basically. Usually VS Code will pick automatically the best option, so their default should work. +Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: -vscode-add-host-ssh-config +```bash +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" +``` -- You should get a pop-up on the bottom right notifying you the host has been added +We'll need to change some values in this file. Here's were you can find the required values: +- **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). +- **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. +- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **instance_user:** in your terminal, run `whoami` and hit enter. -vscode-host-added +After completing this file, it should look similar to: -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` > Pick your VM IP address +```bash +project_id = "wagon-bootcamp" +region = "europe-west1" +zone = "europe-west1-b" +instance_name = "lw-de-vm-tswift" +instance_user = "taylorswift" # result of `whoami` +``` -vscode-add-new-host +Make sure to save the `terraform.tfvars` file and then run: -- The first time, VSCode might ask you for a security permission like below, say yes / continue. +```bash +cd ~/wagon-de-bootcamp -vscode-remote-connection-confirm +terraform init -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Terminal: Create New Terminal (in active workspace)` > You now have a Bash terminal in your virtual machine! +terraform plan +``` -vscode-command-palette-new-terminal -
-vscode-terminal +And check the output, if you have any errors, raise a ticket with a teacher. -- Still on your *local* computer, lets create a more readable version of your machine to connect to! +If everything was successful, create your VM with: ```bash -code ~/.ssh/config +terraform apply -auto-approve ``` -You should see something like the following: +And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. + + +### Virtual Machine connection + +We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. + +To create the VS Code SSH configuration, run the following in your terminal: ```bash -Host - HostName - IdentityFile - User +gcloud compute config-ssh ``` -You can now change Host to whatever you would like to see as the name of your connection or in terminal with `ssh `! -โ—๏ธ It is important that the `Host` alias does not contain any whitespaces โ—๏ธ +You should get an output similar to: ```bash -# For instance -Host "de-bootcamp-vm" - HostName 34.77.50.76 # replace with your VM's public IP address - IdentityFile - User +You should now be able to use ssh/scp with your instances. +For example, try running: + + $ ssh lw-de-vm-tswift.europe-west1-b.wagon-bootcamp +# $ ssh lw-de-vm-.. ``` -**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS code for instance) +To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: +![](/images/vscode_remote_highlight.png) -## VS Code Extensions +It should bring up a menu: -Let's install some useful extensions to VS Code. +![](/images/vscode_remote_menu.png) -- Open your VS Code instance and make sure you're connected to the remote server. At the bottom left, you'll see: +Click on the name of your Virtual Machine: -vscode-ssh +![](/images/vscode_remote_hosts.png) -- Open the VS Code terminal (`CMD` + `` ` `` or `CTRL` + `` ` ``) then run the following commands: +A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. + +![](/images/vscode_remote_fingerprint.png) + +And you are connected! It should look similar too: + +![](/images/vscode_remote_connected.png) + +Notice the connection in the very bottom-left corner of your VS Code window. It should have the Connection type (SSH), and the name of the host you are connected to. + +**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) + + +## Google Authentication + +Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. + +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your Application Default Credentials, in your terminal run: ```bash -code --install-extension ms-vscode.sublime-keybindings -code --install-extension emmanuelbeziat.vscode-great-icons -code --install-extension ms-python.python -code --install-extension KevinRose.vsc-python-indent -code --install-extension ms-python.vscode-pylance -code --install-extension redhat.vscode-yaml -code --install-extension ms-azuretools.vscode-docker -code --install-extension tamasfe.even-better-toml +gcloud auth application-default login ``` -Here is a list of the extensions you are installing: -- [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) -- [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) -- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) -- [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) -- [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) -- [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) -- [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) -- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +### Authenticate gcloud -## Command line tools +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. -### Zsh & Git +To authenticate `gcloud`, run: -Instead of using the default `bash` [shell](https://en.wikipedia.org/wiki/Shell_(computing)), we will use `zsh`. +```bash +gcloud auth login +``` + +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V -We will also use [`git`](https://git-scm.com/), a command line software used for version control. +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. -Let's install them, along with other useful tools: -- Open an **VS Code terminal** connected to your VM -- Copy and paste the following commands: +To set your project, replace `` with your GCP Project ID and run: ```bash -sudo apt update -sudo apt install -y vim tmux tree git ca-certificates curl jq unzip zsh \ -apt-transport-https gnupg software-properties-common direnv sqlite3 make \ -postgresql postgresql-contrib build-essential libssl-dev zlib1g-dev \ -libbz2-dev libreadline-dev libsqlite3-dev wget llvm \ -libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \ -gcc default-mysql-server default-libmysqlclient-dev libpython3-dev openjdk-8-jdk-headless +gcloud config set project ``` -These commands might ask for your password, if they do: type it in. +To confirm your setup, run: -:warning: When you type your password, nothing will show up on the screen, **that's normal**. This is a security feature to mask not only your password as a whole but also its length. Just type in your password and when you're done, press `Enter`. +```bash +gcloud config list +``` + +You should get an output similar to: + +```bash +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] +``` -### GitHub CLI installation -Let's now install [GitHub official CLI](https://cli.github.com) (Command Line Interface). It's a software used to interact with your GitHub account via the command line. +## VM configuration with Ansible -In your terminal, copy-paste the following commands and type in your password if asked: +We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. + +Let's start by confirming that ansible is installed. In your terminal run: ```bash -curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null -sudo apt update -sudo apt install -y gh +ansible --version ``` -To check that `gh` has been successfully installed on your machine, you can run: +You should get an output similar to (some version numbers might change, that's fine): ```bash -gh --version +ansible [core 2.17.9] + config file = /etc/ansible/ansible.cfg + configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /usr/lib/python3/dist-packages/ansible + ansible collection location = /home/tswift/.ansible/collections:/usr/share/ansible/collections + executable location = /usr/bin/ansible + python version = 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3) + jinja version = 3.1.2 + libyaml = True ``` -:heavy_check_mark: If you see `gh version X.Y.Z (YYYY-MM-DD)`, you're good to go :+1: +If not, raise a ticket with a teacher. -:x: Otherwise, please **contact a teacher** +### Ansible Playbook 1 +If everything looks ok, lets create a folder and download the ansible files: -## Oh-my-zsh +```bash +mkdir -p ~/vm-ansible-setup/playbooks -Let's install the `zsh` plugin [Oh My Zsh](https://ohmyz.sh/). +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml +``` -In a terminal execute the following command: +And run with: ```bash -sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part1.yml ``` -If asked "Do you want to change your default shell to zsh?", press `Y` +And the playbook should start running! + +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. -At the end your terminal should look like this: +### What is the playbook installing? -![Ubuntu terminal with OhMyZsh](https://github.com/lewagon/setup/blob/master/images/oh_my_zsh.png) +This playbook is installing a few things, while the playbook is running, let's go through them: +- Updating system packages. Ubuntu uses the `APT` package manager. +- Changing the default shell from **bash** to **zsh**, a more customizable shell that is extensible and looks great! +- Installing the **Oh-My-ZSH** plugin for the **zsh** shell. We'll use it a bit later to add some quality of life plugins and extensions for `zsh`. +- Installing **Docker** on your Virtual Machine. Docker is an open platform for developing, shipping, and running applications. You will use it throughout the bootcamp +- Installing some **Kubernetes (k8s)** tooling: Kubernetes is a system designed to for auto-scaling containerized applications. + - Installing **kubectl**: `kubectl` is the CLI tool for interacting with kubernetes clusters. + - Installing **minikube**: Minikube is a way to quickly spin up a local kubernetes cluster. Great for developing! +- Installing **terraform**: we've already installed it once, but we need to install it on our VM! **Terraform** is an Infrastructure as Code (IaC) tool. +- Install the **GitHub CLI**: the CLI tool that we'll use to interact with your GitHub account directly from the terminal. -:heavy_check_mark: If it does, you can continue :+1: +The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -:x: Otherwise, please **ask for a teacher** +Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: + +![](/images/vscode_after_ansible1.png) ## GitHub CLI @@ -649,120 +750,6 @@ gh auth status :x: If not, **contact a teacher**. -## Google Cloud CLI - -Install the `gcloud` CLI to communicate with [Google Cloud Platform](https://cloud.google.com/) through your terminal: -```bash -echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list -sudo apt-get install apt-transport-https ca-certificates gnupg -curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - -sudo apt-get update && sudo apt-get install google-cloud-sdk -sudo apt-get install google-cloud-sdk-app-engine-python -``` -๐Ÿ‘‰ [Install documentation](https://cloud.google.com/sdk/docs/install#deb) - -### Create a service account key ๐Ÿ”‘ - -**๐Ÿ‘Œ Note: Skip to the next section if you already have a service account key** - -Now that you have created a `GCP account` and a `project` (identified by its `PROJECT_ID`), we are going to configure the actions (API calls) that you want to allow your code to perform. - -
- ๐Ÿค” Why do we need a service account key ? - - - You have created a `GCP account` linked to your credit card. Your account will be billed according to your usage of the ressources of the **Google Cloud Platform**. The billing will occur if you consume anything once the free trial is over, or if you exceed the amount of spending allowed during the free trial. - - In your `GCP account`, you have created a single `GCP project`, identified by its `PROJECT_ID`. The `GCP projects` allow you to organize and monitor more precisely how you consume the **GCP** ressources. For the purpose of the bootcamp, we are only going to create a single project. - - Now, we need a way to tell which ressources within a `GCP project` our code will be allowed to consume. Our code consumes GCP ressources through API calls. - - Since API calls are not free, it is important to define with caution how our code will be allowed to use them. During the bootcamp this will not be an issue and we are going to allow our code to use all the API of **GCP** without any restrictions. - - In the same way that there may be several projects associated with a GCP account, a project may be composed of several services (any bundle of code, whatever its form factor, that requires the usage of GCP API calls in order to fulfill its purpose). - - GCP requires that the services of the projects using API calls are registered on the platform and their credentials configured through the access granted to a `service account`. - - For the moment we will only need to use a single service and will create the corresponding `service account`. -
- -Since the [service account](https://cloud.google.com/iam/docs/service-accounts) is what identifies your application (and therefore your GCP billing account and ultimately your credit card), you are going to want to be cautious with the next steps. - -โš ๏ธ **Do not share you service account json file ๐Ÿ”‘** โš ๏ธ Do not store it on your desktop, do not store it in your git codebase (even if your git repository is private), do not let it by the coffee machine, do not send it as a tweet. - -- Go to the [service accounts page](https://console.cloud.google.com/apis/credentials/serviceaccountkey) -- Select your project in the list of recent projects if asked to -- Create a service account: - - Click on **CREATE SERVICE ACCOUNT**: - - Give a `Service account name` to that account - - Click on **CREATE AND CONTINUE** - - Click on **Select a role** and choose `Quick access/Basic` then **Owner**, which gives full access to all ressources - - Click on **CONTINUE** - - Click on **DONE** -- Download the service account json file ๐Ÿ”‘: - - Click on the newly created service account - - Click on **KEYS** - - Click on **ADD KEY** then **Create new key** - - Select **JSON** and click on **CREATE** - -![](images/gcp_create_key.png) - -The browser has now saved the service account json file ๐Ÿ”‘ in your downloads directory (it is named according to your service account name, something like `le-wagon-data-123456789abc.json`) - - -### Configure Cloud sdk - -- Open the service account json file with any text editor and copy the key - ``` - # It looks like: - { - "type": "service_account", - "project_id": "kevin-bootcamp", - "private_key_id": "1234567890", - "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n", - "client_email": "bootcamp@kevin-bootcamp.iam.gserviceaccount.com", - "client_id": "1234567890", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/bootcamp%40kevin-bootcamp.iam.gserviceaccount.com" - } - ``` -- **on your Virtual Machine**, create a `~/.gcp_keys` directory, then create a json file in it: - ``` bash - mkdir ~/.gcp_keys - touch ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` -- Open the json file then store the service account json file pasting the key: - ```bash - code ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` - ![service account json key](images/service_account_json_key.png) - - โ—๏ธDon't forget to **save** the file with `CMD` + `s` or `CTRL` + `s` - -- Authenticate the `gcloud` CLI with the google account you used for GCP - ```bash - # Replace service_account_name@project_id.iam.gserviceaccount.com with your own - SERVICE_ACCOUNT_EMAIL=service_account_name@project_id.iam.gserviceaccount.com - KEY_FILE=$HOME/.gcp_keys/le-wagon-de-bootcamp.json - gcloud auth activate-service-account $SERVICE_ACCOUNT_EMAIL --key-file=$KEY_FILE - ``` -- List your active account and check your email address you used for GCP is present - ```bash - gcloud auth list - ``` -- Set your current project - ```bash - # Replace `PROJECT_ID` with the `ID` of your project, e.g. `wagon-bootcamp-123456` - gcloud config set project PROJECT_ID - ``` -- List your active account and current project and check your project is present - ```bash - gcloud config list - ``` - - ## Dotfiles Let's pimp your zsh and and vscode by installing lewagon recommanded dotfiles **on your Virtual Machine** @@ -909,491 +896,327 @@ you don't want your email to appear in public repositories you may contribute to -### zsh default terminal - -Set `zsh` as your default VS Code terminal. - -- Open terminal default profile settings - - Terminal profile settings -- Select `zsh /usr/bin/zsh` +## VM configuration with Ansible - Part 2 - Terminal zsh profile +### Ansible Playbook 2 +We'll be using a second **ansible** playbook to further configure your Virtual Machine. -## Disable SSH passphrase prompt - -You don't want to be asked for your passphrase every time you communicate with a distant repository. So, you need to add the plugin `ssh-agent` to `oh my zsh`: - -First, open the `.zshrc` file: +Start by downloading the ansible playbook: ```bash -code ~/.zshrc +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml ``` -Then: -- Spot the line starting with `plugins=` -- Add `ssh-agent` at the end of the plugins list - -:heavy_check_mark: Save the `.zshrc` file with `Ctrl` + `S` and close your text editor. - - -## Docker ๐Ÿ‹ - -Docker is an open platform for developing, shipping, and running applications. - -### Install Docker and Docker Compose - -Setup the dock apt repo - -```bash -sudo install -m 0755 -d /etc/apt/keyrings - -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg - -sudo chmod a+r /etc/apt/keyrings/docker.gpg -``` +And run with: ```bash -echo \ - "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ - "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part2.yml ``` -Install the right packages +And the playbook should start running! -``` -sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -``` +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. -Finally give your user permission to use `docker` +### What is the playbook installing? -```bash -sudo groupadd docker -sudo usermod -aG docker $USER -newgrp docker -``` +This playbook is installing and configuring a things, while the playbook is running, let's go through them: -Run `docker run hello-world`, you should see something like: +**Python and Poetry** -
- โ—๏ธ Permission denied while trying to connect to the Docker daemon socket. โ—๏ธ +Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python [3.12.8](https://www.python.org/downloads/release/python-3128/) -If you receive an error similar to the one below, navigate to the [GCP Compute Engine Console](https://console.cloud.google.com/compute/instances) and shut down your VM by selecting the tick box next to your VM instance and clicking STOP (closing and reopening VSCode is not enough). +- Install **pyenv** and **pyenv-virtualenv**. We'll use **pyenv** to manage the Python versions installed on the VM +- Install Python 3.12.8 with pyenv +- Install **pipx**: [Pipx](https://pipx.pypa.io/stable/) is used to install python packages we want _globally_ available while still using virtual environments, like Poetry! +- Installing a few global python packages with **pipx**: + - **Poetry:** [Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. + - **Ruff:** [Ruff](https://docs.astral.sh/ruff/) Is used to format and lint Python code. + - **tldr:** [tldr](https://github.com/tldr-pages/tldr) has much more readable version of `man` pages. Useful for quickly finding out how a program works. -![](images/docker_permission_denied_socket.png) +**VS Code Configuration** -It will take a few minutes for your VM to turn off. Once it's fully off, turn your VM on again by checking the box next to the VM instance and clicking START. Give the VM a few minutes to fully start up and connect through VSCode. Once connected try `docker run hello-world` again. If you don't get an output similar to the below image, raise a ticket with a teacher. -
+- Installing some **VS Code** extensions, but only on your VM. Here's a list of the extensions that are being installed: + - [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) + - [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) + - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + - [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) + - [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) + - [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) + - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + - [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +- Update the VS Code Python Interpreter path. -![](images/docker_hello.png) +**Shell and System Configuration** -### Enable Artifact Registry API +- Create the **direnv** poetry function. The same one from the lecture! This makes it easier to work with poetry. +- Adding some **Oh-My-ZSH** Plugins: by modifying your `.zshrc` file. Here's a list of the extra plugins: + - **pyenv**: Auto-complete for pyenv, a tool used to manage python virtual environments + - **gcloud**: Auto-complete for the gcloud CLI tool + - **ssh-agent**: Saves your SSH password so you only have to enter it once per session. + - **direnv**: A tool to load `.envrc` files when you `cd` into a directory. Great for loading environment variables. +- Installing **Spark**: Spark is a distributed data processing framework -**๐Ÿ‘Œ Note: Skip to the next section if you already have an Artifact Registry repository** +**Data Engineering Challenges Repository** -[Artifact Registry](https://cloud.google.com/artifact-registry) is a GCP service you will use to store artifacts such as Docker images. The storage units are called repositories. +The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -- Enable the service within your project using the `gcloud` CLI: - ```bash - gcloud services enable artifactregistry.googleapis.com - ``` -- Create a new Docker repository: - ```bash - # Set the repository name - REPOSITORY=docker-hub - # Set the location of the repository. Available locations: gcloud artifacts locations list - LOCATION=europe-west1 - gcloud artifacts repositories create $REPOSITORY \ - --repository-format=docker \ - --location=$LOCATION \ - --description="Docker images storage" - ``` +Here is an image of how the Repository setup works: -### Gcloud authentication for Docker +![](/images/repo_overview.png) -You need to grant Docker access to push artifacts to (and pull from) your repository. There are different authentication methods, [gcloud credentials helper](https://cloud.google.com/artifact-registry/docs/docker/authentication#gcloud-helper) being the easiest. +This allows you to work on challenges, but if we push any changes to the content, you can still access them! -- Define the repository hostname matching the repository `$LOCATION`: - ```bash - # If $LOCATION is "europe-west1" - HOSTNAME=europe-west1-docker.pkg.dev - ``` -- Configure gcloud credentials helper: - ```bash - gcloud auth configure-docker $HOSTNAME - ``` -- Type `y` to accept the configuration -- Check your credentials helper is set: - ```bash - cat ~/.docker/config.json - ``` - You should get: - ```bash - { - "credHelpers": { - "europe-west1-docker.pkg.dev": "gcloud" - } - }% - ``` +### Restart Virtual Machine +Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). -## Kubernetes -Kubernetes (K8s) is a system designed to make deploying auto-scaling containerized applications easily. +To shutdown your VM, navigate to the GCP Compute Engine Instances [console page ๐Ÿ”—](https://console.cloud.google.com/compute/instances). -### Install kubectl -Kubectl is the cli for interacting with k8s! +Select your VM instance and click on the stop button: -https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ +![](/images/gcp_vm_stop.png) -```bash -curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256" +Wait for a few minutes until the VM shows that it is completely off. You may need to refresh the page, the GCP Console doesn't dynamically update. -echo "$(cat kubectl.sha256) kubectl" | sha256sum --check +When the VM is completely off, turn it on again by selecting the check box next to your instance and clicking **START/RESUME**. Give it a minute to spin up, then connect via VS Code. -sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl -kubectl version --client -kubectl version --client --output=yaml -``` +## Check your Virtual Machine Setup -### Install minikube +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. -Minikube is a way to quickly spin up a local kubernetes cluster! +โ— If any of these checks error out, raise a ticket with a teacher. -https://minikube.sigs.k8s.io/docs/start/ +#### Python -```bash -curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 -sudo install minikube-linux-amd64 /usr/local/bin/minikube -``` +To test: -### Test installation -To test that you can launch a cluster run: ```bash -minikube start +python --version ``` -you should see your cluster booting up : -![](images/minikube_start.png) +Should return: -Then to check the cluster run: ```bash -kubectl get po -A +Python 3.12.8 ``` -you should be able to see your cluster running! : -![](images/minikube_base.png) +#### Pyenv -To tear it all down for now: +To test: ```bash -minikube delete --all +pyenv versions ``` +Should return: -## Terraform - -Terraform is a tool for infrastructure as code (IAC) to define resources to create in the cloud! - -### Install terraform - -Install some basic requirements ```bash -sudo apt-get update && sudo apt-get install -y gnupg software-properties-common + system +* 3.12.8 (set by /home//.pyenv/version) ``` -Terraform is not avaliable to apt by default so we need to make it avaliable! -```bash -wget -O- https://apt.releases.hashicorp.com/gpg | \ - gpg --dearmor | \ - sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null -``` +Note: There should be an `*` next to 3.12.8 -```bash -gpg --no-default-keyring \ - --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ - --fingerprint -``` +#### Pipx -```bash -echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ - https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ - sudo tee /etc/apt/sources.list.d/hashicorp.list -``` +To test: -Now we can install terraform directly with apt ๐Ÿ‘‡ ```bash -sudo apt update -sudo apt-get install terraform +pipx list ``` -Verify the installation with: +Should return something similar too: ```bash -terraform --version +venvs are in /home//.local/share/pipx/venvs +apps are exposed on your $PATH at /home//.local/bin +manual pages are exposed at /home//.local/share/man + package poetry 2.1.1, installed using Python 3.12.8 + - poetry + package ruff 0.11.0, installed using Python 3.12.8 + - ruff + package tldr 3.3.0, installed using Python 3.12.8 + - tldr + - man1/tldr.1 ``` +#### Data Engineering Challenges repo remotes - -## Spark - -Spark is a data processing framework: - -Move to your home directory: +To test: ```bash -cd ~ -``` - -Download spark: - -```bash -wget https://archive.apache.org/dist/spark/spark-3.5.3/spark-3.5.3-bin-hadoop3.tgz +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v ``` -Open the tarball: +Should return: ```bash -mkdir -p ~/spark && tar -xzf spark-3.5.3-bin-hadoop3.tgz -C ~/spark +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) ``` -Set the environment variables needed by spark: - -```bash -echo "export SPARK_HOME=$HOME/spark/spark-3.5.3-bin-hadoop3" >> .zshrc -echo 'export PATH=$PATH:$SPARK_HOME/bin' >> .zshrc -``` +#### Docker -Let's restart our shell: +To test: ```bash -exec zsh +docker run hello-world ``` -Test Spark works by running: +Should return: ```bash -spark-shell -``` - -You should see an output similar to: +Unable to find image 'hello-world:latest' locally +latest: Pulling from library/hello-world +e6590344b1a5: Pull complete +Digest: sha256:7e1a4e2d11e2ac7a8c3f768d4166c2defeb09d2a750b010412b6ea13de1efb19 +Status: Downloaded newer image for hello-world:latest -```bash -Setting default log level to "WARN". -To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). -25/01/15 11:33:07 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable -Spark context Web UI available at http://de-vm-lrae-test.europe-north1-b.c.wagon-de.internal:4040 -Spark context available as 'sc' (master = local[*], app id = local-1736940788403). -Spark session available as 'spark'. -Welcome to - ____ __ - / __/__ ___ _____/ /__ - _\ \/ _ \/ _ `/ __/ '_/ - /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 - /_/ +Hello from Docker! +This message shows that your installation appears to be working correctly. -Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_432) -Type in expressions to have them evaluated. -Type :help for more information. +To generate this message, Docker took the following steps: + 1. The Docker client contacted the Docker daemon. + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. + (amd64) + 3. The Docker daemon created a new container from that image which runs the + executable that produces the output you are currently reading. + 4. The Docker daemon streamed that output to the Docker client, which sent it + to your terminal. -scala> -``` -Type `:quit` and hit enter to exit the spark-shell and continue. +To try something more ambitious, you can run an Ubuntu container with: + $ docker run -it ubuntu bash +Share images, automate workflows, and more with a free Docker ID: + https://hub.docker.com/ -## Python & Pip - -Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python 3.12 ([3.12.8](https://www.python.org/downloads/release/python-3128/)). - -Let's install pyenv to manage our python versions: - -```bash -git clone https://github.com/pyenv/pyenv.git ~/.pyenv -source ~/.zprofile -exec zsh +For more examples and ideas, visit: + https://docs.docker.com/get-started/ ``` -We'll also install a useful `pyenv` plugin called [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv). Although we will be using `poetry` for Python package and virtual environment management, `pyenv-virtualenv` is useful for controlling python versions locally. +#### Kubernetes -```bash -git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv -exec zsh -``` +We can start by testing `minikube`: -Now install Python 3.12.8: ```bash -pyenv install 3.12.8 -pyenv global 3.12.8 -``` -Now `python --version` should return `3.12.8` - - -## Pipx - -Next we are going to install [pipx](https://pypa.github.io/pipx/) to install python packages we want globally available while still using virtual environments. - -Let's upgrade `pip` first: - -```bash -pip install --upgrade pip +# Start +minikube start ``` -And install `pipx`: +Should return: ```bash -python -m pip install --user pipx # --user so that each ubuntu user can have his own 'pipx' -python -m pipx ensurepath -exec zsh +๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) +โœจ Automatically selected the docker driver. Other choices: none, ssh +๐Ÿ“Œ Using Docker driver with root privileges +๐Ÿ‘ Starting "minikube" primary control-plane node in "minikube" cluster +๐Ÿšœ Pulling base image v0.0.46 ... +๐Ÿ’พ Downloading Kubernetes v1.32.0 preload ... + > gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 88.19 M + > preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 32.20 M +๐Ÿ”ฅ Creating docker container (CPUs=2, Memory=3900MB) ... +๐Ÿณ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ... + โ–ช Generating certificates and keys ... + โ–ช Booting up control plane ... + โ–ช Configuring RBAC rules ... +๐Ÿ”— Configuring bridge CNI (Container Networking Interface) ... +๐Ÿ”Ž Verifying Kubernetes components... + โ–ช Using image gcr.io/k8s-minikube/storage-provisioner:v5 +๐ŸŒŸ Enabled addons: storage-provisioner, default-storageclass +๐Ÿ„ Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default ``` -Lets install a [tldr](https://github.com/tldr-pages/tldr) with pipx +And then make sure the kubernetes CLI utility, `kubectl`, works with: ```bash -pipx install tldr +# Get pods +kubectl get po -A ``` -Now `tldr` should be globally available (for the current user), test it out with: +Should return something similar too: ```bash -tldr ls +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s +kube-system etcd-minikube 1/1 Running 0 78s +kube-system kube-apiserver-minikube 1/1 Running 0 76s +kube-system kube-controller-manager-minikube 1/1 Running 0 76s +kube-system kube-proxy-stk77 1/1 Running 0 72s +kube-system kube-scheduler-minikube 1/1 Running 0 76s +kube-system storage-provisioner 1/1 Running 1 (41s ago) 75s ``` -Much more readable than the classic `man ls` (although sometimes you will still need to delve into the man pages to get all of the details!) and it even has pages not included in man such as `tldr gh`: - -tldr - - -Lets add a few more packages we want globally available - -### black - -[black](https://black.readthedocs.io/en/stable/) for helping to format code +And because `minikube` is resource intensive, stop it for now with: ```bash -pipx install black -``` - -### Poetry - -[Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. - -Install Poetry running the following command in your VS Code terminal: - -```bash -pipx install poetry +# Stop +minikube delete --all ``` -Then, let's update default poetry behavior so that virtual envs are always created where `poetry install` is run. -During the bootcamp, you'll see a `.venv` folder being created inside each challenge folder. +Should return: ```bash -poetry config virtualenvs.in-project true -``` - -Finally, update your VScode settings to tell it that this `.venv` relative folder path will be your default interpreter! - -1. Open the Command Palette ( ๐ŸชŸ ctrl + shift + P / ๐ŸŽ cmd + shift + P ) -2. Search for: **Preference: Open Remote Settings (JSON)** - when you open your settings that should be two panels. -3. In the panel that opens on the **right side** search for the line: `python.defaultInterpreterPath` -4. Replace the value (probably `"~/.pyenv/shims/python"`) so that it looks like: - -```yml -"python.defaultInterpreterPath": ".venv/bin/python", +๐Ÿ”ฅ Deleting "minikube" in docker ... +๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... +๐Ÿ’€ Removed all traces of the "minikube" cluster. +๐Ÿ”ฅ Successfully deleted all profiles ``` -## Direnv - -[Direnv](https://direnv.net/) is a great utility that will look for `.envrc` files in your directories. When you `cd` into directories with a `.envrc` files, paths will automatically be updated. In our case, this will simplify our workflow and allow us to not have to worry about Poetry managed Python virtual environments. +#### Terraform -1. First, setup the *direnv hook* to your zsh shell so that direnv gets activated anytime a `.envrc` file exists in current working directory. - -```bash -code ~/.zshrc -``` +To test: ```bash -plugins=(git gitfast ... pyenv ssh-agent direnv) # add `direnv` to the existing list of plugins +terraform --version ``` -2. Second, let's configure what will happens anytime `.envrc` file is found +Should return: ```bash -code ~/.direnvrc +Terraform v1.11.2 +on linux_amd64 ``` -- Paste the following lines - ```bash - layout_poetry() { - if [[ ! -f pyproject.toml ]]; then - log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.' - exit 2 - fi - # create venv if it doesn't exist - poetry run true - - export VIRTUAL_ENV=$(poetry env info --path) - export POETRY_ACTIVE=1 - PATH_add "$VIRTUAL_ENV/bin" - } - ``` -- Save and close the file - -๐Ÿ˜Ž Now, **anytime you `cd` into a challenge folder which contains a `.envrc` file which contains `layout_poetry()` command inside, the function will get executed and your virtual env will switch to the poetry one that is defined by the `pyproject.toml` !** -- No need to prefix all commands with `poetry run `, but simply `` -- Each challenge will have its own virtual env, and it will be seamless for you to switch between challenges/envs +#### Spark -## Let's Make! - -Lets clone the challenges onto your **virtual machine** +To test: ```bash -export GITHUB_USERNAME=`gh api user | jq -r '.login'` -echo $GITHUB_USERNAME -``` - -Then: - -```bash -mkdir -p ~/code/$GITHUB_USERNAME && cd $_ -gh repo fork lewagon/data-engineering-challenges --clone +spark-shell ``` -Our setup will look a bit like this: - - - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - -Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! +Should take you into the spark shell that looks like: ```bash -cd data-engineering-challenges -git remote -v -# origin git@github.com:your_github_username/data-engineering-challenges.git (fetch) -# origin git@github.com:your_github_username/data-engineering-challenges.git (push) -# upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -# upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - -From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: - -- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) -- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) -- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder +Setting default log level to "WARN". +To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). +25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable +Spark context Web UI available at http://lw-de-vm.europe-north1-b.c.wagon-de.internal:4040 +Spark context available as 'sc' (master = local[*], app id = local-1742288096829). +Spark session available as 'spark'. +Welcome to + ____ __ + / __/__ ___ _____/ /__ + _\ \/ _ \/ _ `/ __/ '_/ + /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 + /_/ -Let's make! +Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_442) +Type in expressions to have them evaluated. +Type :help for more information. -```bash -make install +scala> ``` -This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. +Type `:quit` and hit enter to exit the spark-shell and continue. -โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ +That's everything for now! diff --git a/WINDOWS.md b/WINDOWS.md index 2ec99aa..69585a2 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -6,6 +6,42 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: +This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! +- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! + +## Part 1: Setup your local computer + +In this section you'll setup your local computer and create some accounts. It will include things like: +1. Install some communication tools: Zoom, Slack +2. Create some accounts: Github, Google Cloud Platform (GCP) +3. Install Visual Studio Code (VS Code) +4. Install and authentication the GCP command line tool: `gcloud`. +5. Install **terraform** on your local computer. +6. Create your virtual machine with **terraform** and connect to it with **VS Code**! + +## Part 2: Configure your Virtual Machine Part 1 + +All parts of this section happen on your virtual machine. + +This section includes: +1. Authenticate your virtual machine with `gcloud` +2. Download and run an **ansible** playbook to partially configure your virtual machine. +3. Login to the Github command line tool on your virtual machine +4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! + +## Part 3: Configure your Virtual Machine Part 2 + +All parts of this section happen on your virtual machine. + +In this section you will: +1. Download and run a second **ansible** playbook for some more fine tuning. +2. Test your set up to make sure that everything has installed correctly. +3. Create some python environments. + + +Don't worry, we'll go into more detail in each of the individual sections. + Let's start :rocket: @@ -89,62 +125,15 @@ Have you signed up to GitHub? If not, [do it right away](https://github.com/join :point_right: **[Enable Two-Factor Authentication (2FA)](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication#configuring-two-factor-authentication-using-text-messages)**. GitHub will send you text messages with a code when you try to log in. This is important for security and also will soon be required in order to contribute code on GitHub. -## SSH key - -We want to safely communicate with your virtual machine using [SSH protocol](https://en.wikipedia.org/wiki/Secure_Shell). We need to generate a SSH key to authenticate. +## Chrome - your browser -- Open your terminal +Install the Google Chrome browser if you haven't got it already and set it as a __default browser__. -
- ๐Ÿ’ก Windows tip - -We highly recommend installing [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=fr-fr&gl=FR) from the Windows Store (installed on Windows 11 by default) to perform this operation -
+Follow the steps for your system from this link :point_right: [Install Google Chrome](https://support.google.com/chrome/answer/95346?co=GENIE.Platform%3DDesktop&hl=en-GB) -- Create a SSH key - -
- Windows - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen.exe -t ed25519 -C "your_email@example.com" -``` -
- -
- MacOS & Linux - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -C "your_email@example.com" -``` -
- - -You should get the following message: `> Generating public/private algorithm key pair.` -- When you are prompted `> Enter a file in which to save the key`, press Enter -- You should be asked to `Enter a passphrase` - this is optional if you want additional security. To continue without a passphrase press enter without typing anything when asked to enter a passphrase. - -โ„น๏ธ Don't worry if nothing prompt when you type, that is perfectly normal for security reasons. - -- You should be asked to `Enter same passphrase again`, do it. - -**โ—๏ธ You must remember this passphrase.** - -
- โ—๏ธ /home/your_username/.ssh/id_ed25519 already exists. -If you receive this message, you may already have an SSH Key with the same name (if you are a Le Wagon Alumni or are using SSH Authentication with Github). - -To create a separate SSH key to exclusively use for this bootcamp use the following: - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -f ~/.ssh/de-bootcamp -C "your_email@example.com" -``` +__Why Chrome?__ -Your new SSH Key will be named `de-bootcamp`. Make sure to remember it for later! -
+We recommend to use it as your default browser as it's most compatible with testing or running your code, as well as working with Google Cloud Platform. Another alternative is Firefox, however we don't recommend using other tools like Opera, Internet Explorer or Safari. ## Google Cloud Platform setup @@ -287,281 +276,365 @@ Go to your project [APIs dashboard](https://console.cloud.google.com/apis/dashbo - Compute Engine is now enabled on your project -## Virtual Machine (VM) +## Visual Studio Code -**๐Ÿ‘Œ Note: Skip to the next section if you already have a VM set up** +### Installation -_Note: The following section requires you already have a [Google Cloud Platform](https://cloud.google.com/) account associated with an active [Billing account](https://console.cloud.google.com/billing)._ +Let's install [Visual Studio Code](https://code.visualstudio.com) text editor. -- Go to console.cloud.google.com > > Compute Engine > VM instances > Create instance -- Name it `lewagon-data-eng-vm-`, replace `` with your own, e.g. `krokrob` -- Region `europe-west1`, choose the closest one among the [available regions](https://cloud.google.com/compute/docs/regions-zones#available) +- Go to [Visual Studio Code download page](https://code.visualstudio.com/download). +- Click on "Windows" button +- Open the file you have just downloaded. +- Install it with few options: - gcloud-console-vm-create-instance -- In the section `Machine configuration` under the sub-heading `Machine type` -- Select General purpose > PRESET > e2-standard-4 +![VS Code installation options](https://github.com/lewagon/setup/blob/master/images/windows_vscode_installation.png) - gcloud-console-vm-e2-standard4 -- Boot disk > Change - - Operating system > Ubuntu - - Version > Ubuntu 22.04 LTS x86/64 - - Boot disk type > Balanced persistent disk - - Size > upgrade to 150GB +When the installation is finished, launch VS Code. - gcloud-console-vm-ubunt -- Open `Networking, Disks, ...` under `Advanced options` -- Open `Networking` - gcloud-console-vm-networking -- Go to `Network interfaces` and click on `default default (...)` with a downward arrow on the right. +### VS Code Remote SSH Extension - gcloud-console-vm-network-interfaces -- This opened a box `Edit network interface` -- Go to the dropdown `External IPv4 address`, click on it, click on `RESERVE STATIC EXTERNAL IP ADDRESS` +We need to connect VS Code to a virtual machine in the cloud so you will only work on that machine during the bootcamp. A pretty useful [**Remote SSH Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) is available on the VS Code Marketplace. - gcloud-console-vm-create-static-ip -- Give it a name, like "lewagon-data-eng-vm-ip-" (replace `` with your own) and description "Le Wagon - Data Engineering VM IP". This will take a few seconds. +- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Extensions: Install Extensions` - gcloud-console-reserve-static-ip +VSCode extensions - Search - Remote -- You will now have a public IP associated with your account, and later to your VM instance. Click on `Done` at the bottom of the section `Edit network interface` you were in. +- Install the extension - gcloud-console-new-external-ip +VS Code extensions - Remote - Details -### Public SSH key -- Open the `Security` section +That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. - gcloud-console-vm-security -- Open the `Manage access` subsection - gcloud-console-manage-access -- Go to `Add manually generated SSH keys` and click `Add item` +## Google Cloud CLI - gcloud-console-add-manual-ssh-key -- In your terminal display your public SSH key: - - Windows: navigate to where you created your SSH key and open `id_ed25519.pub` +The `gcloud` Command Line Interface (CLI) is used to communicate with Google Cloud Platform services through your terminal. - - Mac/Linux users can use: - ```bash - cat ~/.ssh/id_ed25519.pub - # OR cat ~/.ssh/de-bootcamp.pub if you created a unique key - ``` -- Copy your public SSH key and paste it: +### Install gcloud - gcloud-console-add-ssh-key-pub -- On the right hand side you should see - gcloud-console-vm-price-month -- You should be good to go and click `CREATE` at the bottom +To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). - gcloud-console-vm-create -- It will take a few minutes for your virtual machine (VM) to be created. Your instance will show up like below when ready, with a green circled tick, named `lewagon-data-eng-vm-krokrob` (`krokrob` being replaced by your GitHub username). +Once it's finished downloading, launch the installer as administrator and follow the prompts. - gcloud-console-vm-instance-running -- Click on your instance - gcloud-console-vm-running -- Go down to the section `SSH keys`, and write down your username (you need it for the next section) +To test your install, run the following in your terminal: - gcloud-console-vm-username +```bash +gcloud --version +``` -Congrats, your virtual machine is up and running, it is time to connect it with VS Code! +### Authenticate gcloud -## Visual Studio Code +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. -### Installation +To authenticate `gcloud`, run: -Let's install [Visual Studio Code](https://code.visualstudio.com) text editor. +```bash +gcloud auth login +``` -- Go to [Visual Studio Code download page](https://code.visualstudio.com/download). -- Click on "Windows" button -- Open the file you have just downloaded. -- Install it with few options: +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V -![VS Code installation options](https://github.com/lewagon/setup/blob/master/images/windows_vscode_installation.png) +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. -When the installation is finished, launch VS Code. +To set your project, replace `` with your GCP Project ID and run: +```bash +gcloud config set project +``` -### VS Code Remote SSH Extension +To confirm your setup, run: -We need to connect VS Code to a virtual machine in the cloud so you will only work on that machine during the bootcamp. A pretty useful [**Remote SSH Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) is available on the VS Code Marketplace. +```bash +gcloud config list +``` -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Extensions: Install Extensions` +You should get an output similar to: -VSCode extensions - Search - Remote +```bash +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID -- Install the extension +Your active configuration is: [default] +``` -VS Code extensions - Remote - Details -That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. +## Terraform + +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! + +To install terraform, download the binary from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). + +TODO: Unsure if anything needs to be added to PATH to get it to work + +Verify the installation with: + +```bash +terraform --version +``` -### Virtual Machine connection -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` +## Provisioning your Virtual Machine with Terraform -vscode-connect-to-host +We're almost at the point of creating your Virtual Machine. -- Click on `Add a new host` -- Type `ssh -i @`, for instance, my username is `somedude`, my private SSH key is located at `~/.ssh/id_rsa` on my local computer, my VM has a public IP of `34.77.50.76`: I'll type `ssh -i ~/.ssh/id_rsa somedude@34.77.50.76` +The specifications of the machine you'll use for the bootcamp are: +- Operation System: Ubuntu 22.04 LTS +- CPU: 4 Virtual CPU cores +- RAM: 16 GB +- Storage: 100 GB +- Network: Static External IP address -vscode-ssh-connection-command +### Cost ๐Ÿ’ธ +Creating and running a Virtual Machine on Google Cloud Platform costs money. -- When prompted to `Select SSH configuration file to update`, pick the one in your home directory, under the `.ssh` folder, `~/.ssh/config` basically. Usually VS Code will pick automatically the best option, so their default should work. +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -vscode-add-host-ssh-config +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! -- You should get a pop-up on the bottom right notifying you the host has been added +You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. -vscode-host-added +### Download terraform files -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` > Pick your VM IP address +We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. -vscode-add-new-host +First we'll create a folder and download the terraform files with: -- The first time, VSCode might ask you for a security permission like below, say yes / continue. +Using the Command Prompt (cmd), run the following: -vscode-remote-connection-confirm +TODO: Requires testing -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Terminal: Create New Terminal (in active workspace)` > You now have a Bash terminal in your virtual machine! +```cmd +mkdir %USERPROFILE%\wagon-de-bootcamp +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\main.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\provider.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\variables.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\terraform.tfvars" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o "%USERPROFILE%\wagon-de-bootcamp\.terraform.lock.hcl" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` + + +### Set variables + +Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: + +```bash +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" +``` + +We'll need to change some values in this file. Here's were you can find the required values: +- **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). +- **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. +- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **instance_user:** in your terminal, run `whoami` and hit enter. + +After completing this file, it should look similar to: + +```bash +project_id = "wagon-bootcamp" +region = "europe-west1" +zone = "europe-west1-b" +instance_name = "lw-de-vm-tswift" +instance_user = "taylorswift" # result of `whoami` +``` + +Make sure to save the `terraform.tfvars` file and then run: + +```bash +cd ~/wagon-de-bootcamp + +terraform init + +terraform plan +``` -vscode-command-palette-new-terminal -
-vscode-terminal +And check the output, if you have any errors, raise a ticket with a teacher. -- Still on your *local* computer, lets create a more readable version of your machine to connect to! +If everything was successful, create your VM with: ```bash -code ~/.ssh/config +terraform apply -auto-approve ``` -You should see something like the following: +And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. + + +### Virtual Machine connection + +We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. + +To create the VS Code SSH configuration, run the following in your terminal: ```bash -Host - HostName - IdentityFile - User +gcloud compute config-ssh ``` -You can now change Host to whatever you would like to see as the name of your connection or in terminal with `ssh `! -โ—๏ธ It is important that the `Host` alias does not contain any whitespaces โ—๏ธ +You should get an output similar to: ```bash -# For instance -Host "de-bootcamp-vm" - HostName 34.77.50.76 # replace with your VM's public IP address - IdentityFile - User +You should now be able to use ssh/scp with your instances. +For example, try running: + + $ ssh lw-de-vm-tswift.europe-west1-b.wagon-bootcamp +# $ ssh lw-de-vm-.. ``` -**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS code for instance) +To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: + +![](/images/vscode_remote_highlight.png) + +It should bring up a menu: + +![](/images/vscode_remote_menu.png) + +Click on the name of your Virtual Machine: +![](/images/vscode_remote_hosts.png) -## VS Code Extensions +A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. -Let's install some useful extensions to VS Code. +![](/images/vscode_remote_fingerprint.png) -- Open your VS Code instance and make sure you're connected to the remote server. At the bottom left, you'll see: +And you are connected! It should look similar too: -vscode-ssh +![](/images/vscode_remote_connected.png) -- Open the VS Code terminal (`CMD` + `` ` `` or `CTRL` + `` ` ``) then run the following commands: +Notice the connection in the very bottom-left corner of your VS Code window. It should have the Connection type (SSH), and the name of the host you are connected to. + +**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) + + +## Google Authentication + +Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. + +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your Application Default Credentials, in your terminal run: ```bash -code --install-extension ms-vscode.sublime-keybindings -code --install-extension emmanuelbeziat.vscode-great-icons -code --install-extension ms-python.python -code --install-extension KevinRose.vsc-python-indent -code --install-extension ms-python.vscode-pylance -code --install-extension redhat.vscode-yaml -code --install-extension ms-azuretools.vscode-docker -code --install-extension tamasfe.even-better-toml +gcloud auth application-default login ``` -Here is a list of the extensions you are installing: -- [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) -- [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) -- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) -- [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) -- [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) -- [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) -- [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) -- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +### Authenticate gcloud -## Command line tools +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. -### Zsh & Git +To authenticate `gcloud`, run: -Instead of using the default `bash` [shell](https://en.wikipedia.org/wiki/Shell_(computing)), we will use `zsh`. +```bash +gcloud auth login +``` -We will also use [`git`](https://git-scm.com/), a command line software used for version control. +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V -Let's install them, along with other useful tools: -- Open an **VS Code terminal** connected to your VM -- Copy and paste the following commands: +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. + +To set your project, replace `` with your GCP Project ID and run: + +```bash +gcloud config set project +``` + +To confirm your setup, run: ```bash -sudo apt update -sudo apt install -y vim tmux tree git ca-certificates curl jq unzip zsh \ -apt-transport-https gnupg software-properties-common direnv sqlite3 make \ -postgresql postgresql-contrib build-essential libssl-dev zlib1g-dev \ -libbz2-dev libreadline-dev libsqlite3-dev wget llvm \ -libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \ -gcc default-mysql-server default-libmysqlclient-dev libpython3-dev openjdk-8-jdk-headless +gcloud config list ``` -These commands might ask for your password, if they do: type it in. +You should get an output similar to: + +```bash +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] +``` -:warning: When you type your password, nothing will show up on the screen, **that's normal**. This is a security feature to mask not only your password as a whole but also its length. Just type in your password and when you're done, press `Enter`. -### GitHub CLI installation +## VM configuration with Ansible -Let's now install [GitHub official CLI](https://cli.github.com) (Command Line Interface). It's a software used to interact with your GitHub account via the command line. +We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. -In your terminal, copy-paste the following commands and type in your password if asked: +Let's start by confirming that ansible is installed. In your terminal run: ```bash -curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null -sudo apt update -sudo apt install -y gh +ansible --version ``` -To check that `gh` has been successfully installed on your machine, you can run: +You should get an output similar to (some version numbers might change, that's fine): ```bash -gh --version +ansible [core 2.17.9] + config file = /etc/ansible/ansible.cfg + configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /usr/lib/python3/dist-packages/ansible + ansible collection location = /home/tswift/.ansible/collections:/usr/share/ansible/collections + executable location = /usr/bin/ansible + python version = 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3) + jinja version = 3.1.2 + libyaml = True ``` -:heavy_check_mark: If you see `gh version X.Y.Z (YYYY-MM-DD)`, you're good to go :+1: +If not, raise a ticket with a teacher. -:x: Otherwise, please **contact a teacher** +### Ansible Playbook 1 +If everything looks ok, lets create a folder and download the ansible files: -## Oh-my-zsh +```bash +mkdir -p ~/vm-ansible-setup/playbooks -Let's install the `zsh` plugin [Oh My Zsh](https://ohmyz.sh/). +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml +``` -In a terminal execute the following command: +And run with: ```bash -sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part1.yml ``` -If asked "Do you want to change your default shell to zsh?", press `Y` +And the playbook should start running! + +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. -At the end your terminal should look like this: +### What is the playbook installing? -![Ubuntu terminal with OhMyZsh](https://github.com/lewagon/setup/blob/master/images/oh_my_zsh.png) +This playbook is installing a few things, while the playbook is running, let's go through them: +- Updating system packages. Ubuntu uses the `APT` package manager. +- Changing the default shell from **bash** to **zsh**, a more customizable shell that is extensible and looks great! +- Installing the **Oh-My-ZSH** plugin for the **zsh** shell. We'll use it a bit later to add some quality of life plugins and extensions for `zsh`. +- Installing **Docker** on your Virtual Machine. Docker is an open platform for developing, shipping, and running applications. You will use it throughout the bootcamp +- Installing some **Kubernetes (k8s)** tooling: Kubernetes is a system designed to for auto-scaling containerized applications. + - Installing **kubectl**: `kubectl` is the CLI tool for interacting with kubernetes clusters. + - Installing **minikube**: Minikube is a way to quickly spin up a local kubernetes cluster. Great for developing! +- Installing **terraform**: we've already installed it once, but we need to install it on our VM! **Terraform** is an Infrastructure as Code (IaC) tool. +- Install the **GitHub CLI**: the CLI tool that we'll use to interact with your GitHub account directly from the terminal. -:heavy_check_mark: If it does, you can continue :+1: +The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -:x: Otherwise, please **ask for a teacher** +Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: + +![](/images/vscode_after_ansible1.png) ## GitHub CLI @@ -616,120 +689,6 @@ gh auth status :x: If not, **contact a teacher**. -## Google Cloud CLI - -Install the `gcloud` CLI to communicate with [Google Cloud Platform](https://cloud.google.com/) through your terminal: -```bash -echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list -sudo apt-get install apt-transport-https ca-certificates gnupg -curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - -sudo apt-get update && sudo apt-get install google-cloud-sdk -sudo apt-get install google-cloud-sdk-app-engine-python -``` -๐Ÿ‘‰ [Install documentation](https://cloud.google.com/sdk/docs/install#deb) - -### Create a service account key ๐Ÿ”‘ - -**๐Ÿ‘Œ Note: Skip to the next section if you already have a service account key** - -Now that you have created a `GCP account` and a `project` (identified by its `PROJECT_ID`), we are going to configure the actions (API calls) that you want to allow your code to perform. - -
- ๐Ÿค” Why do we need a service account key ? - - - You have created a `GCP account` linked to your credit card. Your account will be billed according to your usage of the ressources of the **Google Cloud Platform**. The billing will occur if you consume anything once the free trial is over, or if you exceed the amount of spending allowed during the free trial. - - In your `GCP account`, you have created a single `GCP project`, identified by its `PROJECT_ID`. The `GCP projects` allow you to organize and monitor more precisely how you consume the **GCP** ressources. For the purpose of the bootcamp, we are only going to create a single project. - - Now, we need a way to tell which ressources within a `GCP project` our code will be allowed to consume. Our code consumes GCP ressources through API calls. - - Since API calls are not free, it is important to define with caution how our code will be allowed to use them. During the bootcamp this will not be an issue and we are going to allow our code to use all the API of **GCP** without any restrictions. - - In the same way that there may be several projects associated with a GCP account, a project may be composed of several services (any bundle of code, whatever its form factor, that requires the usage of GCP API calls in order to fulfill its purpose). - - GCP requires that the services of the projects using API calls are registered on the platform and their credentials configured through the access granted to a `service account`. - - For the moment we will only need to use a single service and will create the corresponding `service account`. -
- -Since the [service account](https://cloud.google.com/iam/docs/service-accounts) is what identifies your application (and therefore your GCP billing account and ultimately your credit card), you are going to want to be cautious with the next steps. - -โš ๏ธ **Do not share you service account json file ๐Ÿ”‘** โš ๏ธ Do not store it on your desktop, do not store it in your git codebase (even if your git repository is private), do not let it by the coffee machine, do not send it as a tweet. - -- Go to the [service accounts page](https://console.cloud.google.com/apis/credentials/serviceaccountkey) -- Select your project in the list of recent projects if asked to -- Create a service account: - - Click on **CREATE SERVICE ACCOUNT**: - - Give a `Service account name` to that account - - Click on **CREATE AND CONTINUE** - - Click on **Select a role** and choose `Quick access/Basic` then **Owner**, which gives full access to all ressources - - Click on **CONTINUE** - - Click on **DONE** -- Download the service account json file ๐Ÿ”‘: - - Click on the newly created service account - - Click on **KEYS** - - Click on **ADD KEY** then **Create new key** - - Select **JSON** and click on **CREATE** - -![](images/gcp_create_key.png) - -The browser has now saved the service account json file ๐Ÿ”‘ in your downloads directory (it is named according to your service account name, something like `le-wagon-data-123456789abc.json`) - - -### Configure Cloud sdk - -- Open the service account json file with any text editor and copy the key - ``` - # It looks like: - { - "type": "service_account", - "project_id": "kevin-bootcamp", - "private_key_id": "1234567890", - "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n", - "client_email": "bootcamp@kevin-bootcamp.iam.gserviceaccount.com", - "client_id": "1234567890", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/bootcamp%40kevin-bootcamp.iam.gserviceaccount.com" - } - ``` -- **on your Virtual Machine**, create a `~/.gcp_keys` directory, then create a json file in it: - ``` bash - mkdir ~/.gcp_keys - touch ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` -- Open the json file then store the service account json file pasting the key: - ```bash - code ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` - ![service account json key](images/service_account_json_key.png) - - โ—๏ธDon't forget to **save** the file with `CMD` + `s` or `CTRL` + `s` - -- Authenticate the `gcloud` CLI with the google account you used for GCP - ```bash - # Replace service_account_name@project_id.iam.gserviceaccount.com with your own - SERVICE_ACCOUNT_EMAIL=service_account_name@project_id.iam.gserviceaccount.com - KEY_FILE=$HOME/.gcp_keys/le-wagon-de-bootcamp.json - gcloud auth activate-service-account $SERVICE_ACCOUNT_EMAIL --key-file=$KEY_FILE - ``` -- List your active account and check your email address you used for GCP is present - ```bash - gcloud auth list - ``` -- Set your current project - ```bash - # Replace `PROJECT_ID` with the `ID` of your project, e.g. `wagon-bootcamp-123456` - gcloud config set project PROJECT_ID - ``` -- List your active account and current project and check your project is present - ```bash - gcloud config list - ``` - - ## Dotfiles Let's pimp your zsh and and vscode by installing lewagon recommanded dotfiles **on your Virtual Machine** @@ -876,491 +835,327 @@ you don't want your email to appear in public repositories you may contribute to -### zsh default terminal - -Set `zsh` as your default VS Code terminal. - -- Open terminal default profile settings - - Terminal profile settings -- Select `zsh /usr/bin/zsh` +## VM configuration with Ansible - Part 2 - Terminal zsh profile +### Ansible Playbook 2 +We'll be using a second **ansible** playbook to further configure your Virtual Machine. -## Disable SSH passphrase prompt - -You don't want to be asked for your passphrase every time you communicate with a distant repository. So, you need to add the plugin `ssh-agent` to `oh my zsh`: - -First, open the `.zshrc` file: +Start by downloading the ansible playbook: ```bash -code ~/.zshrc +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml ``` -Then: -- Spot the line starting with `plugins=` -- Add `ssh-agent` at the end of the plugins list - -:heavy_check_mark: Save the `.zshrc` file with `Ctrl` + `S` and close your text editor. - - -## Docker ๐Ÿ‹ - -Docker is an open platform for developing, shipping, and running applications. - -### Install Docker and Docker Compose - -Setup the dock apt repo - -```bash -sudo install -m 0755 -d /etc/apt/keyrings - -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg - -sudo chmod a+r /etc/apt/keyrings/docker.gpg -``` +And run with: ```bash -echo \ - "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ - "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part2.yml ``` -Install the right packages +And the playbook should start running! -``` -sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -``` +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. -Finally give your user permission to use `docker` +### What is the playbook installing? -```bash -sudo groupadd docker -sudo usermod -aG docker $USER -newgrp docker -``` +This playbook is installing and configuring a things, while the playbook is running, let's go through them: -Run `docker run hello-world`, you should see something like: +**Python and Poetry** -
- โ—๏ธ Permission denied while trying to connect to the Docker daemon socket. โ—๏ธ +Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python [3.12.8](https://www.python.org/downloads/release/python-3128/) -If you receive an error similar to the one below, navigate to the [GCP Compute Engine Console](https://console.cloud.google.com/compute/instances) and shut down your VM by selecting the tick box next to your VM instance and clicking STOP (closing and reopening VSCode is not enough). +- Install **pyenv** and **pyenv-virtualenv**. We'll use **pyenv** to manage the Python versions installed on the VM +- Install Python 3.12.8 with pyenv +- Install **pipx**: [Pipx](https://pipx.pypa.io/stable/) is used to install python packages we want _globally_ available while still using virtual environments, like Poetry! +- Installing a few global python packages with **pipx**: + - **Poetry:** [Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. + - **Ruff:** [Ruff](https://docs.astral.sh/ruff/) Is used to format and lint Python code. + - **tldr:** [tldr](https://github.com/tldr-pages/tldr) has much more readable version of `man` pages. Useful for quickly finding out how a program works. -![](images/docker_permission_denied_socket.png) +**VS Code Configuration** -It will take a few minutes for your VM to turn off. Once it's fully off, turn your VM on again by checking the box next to the VM instance and clicking START. Give the VM a few minutes to fully start up and connect through VSCode. Once connected try `docker run hello-world` again. If you don't get an output similar to the below image, raise a ticket with a teacher. -
+- Installing some **VS Code** extensions, but only on your VM. Here's a list of the extensions that are being installed: + - [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) + - [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) + - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + - [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) + - [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) + - [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) + - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + - [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +- Update the VS Code Python Interpreter path. -![](images/docker_hello.png) - -### Enable Artifact Registry API - -**๐Ÿ‘Œ Note: Skip to the next section if you already have an Artifact Registry repository** - -[Artifact Registry](https://cloud.google.com/artifact-registry) is a GCP service you will use to store artifacts such as Docker images. The storage units are called repositories. - -- Enable the service within your project using the `gcloud` CLI: - ```bash - gcloud services enable artifactregistry.googleapis.com - ``` -- Create a new Docker repository: - ```bash - # Set the repository name - REPOSITORY=docker-hub - # Set the location of the repository. Available locations: gcloud artifacts locations list - LOCATION=europe-west1 - gcloud artifacts repositories create $REPOSITORY \ - --repository-format=docker \ - --location=$LOCATION \ - --description="Docker images storage" - ``` - -### Gcloud authentication for Docker - -You need to grant Docker access to push artifacts to (and pull from) your repository. There are different authentication methods, [gcloud credentials helper](https://cloud.google.com/artifact-registry/docs/docker/authentication#gcloud-helper) being the easiest. - -- Define the repository hostname matching the repository `$LOCATION`: - ```bash - # If $LOCATION is "europe-west1" - HOSTNAME=europe-west1-docker.pkg.dev - ``` -- Configure gcloud credentials helper: - ```bash - gcloud auth configure-docker $HOSTNAME - ``` -- Type `y` to accept the configuration -- Check your credentials helper is set: - ```bash - cat ~/.docker/config.json - ``` - You should get: - ```bash - { - "credHelpers": { - "europe-west1-docker.pkg.dev": "gcloud" - } - }% - ``` - - -## Kubernetes -Kubernetes (K8s) is a system designed to make deploying auto-scaling containerized applications easily. - -### Install kubectl -Kubectl is the cli for interacting with k8s! - -https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ +**Shell and System Configuration** -```bash -curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256" +- Create the **direnv** poetry function. The same one from the lecture! This makes it easier to work with poetry. +- Adding some **Oh-My-ZSH** Plugins: by modifying your `.zshrc` file. Here's a list of the extra plugins: + - **pyenv**: Auto-complete for pyenv, a tool used to manage python virtual environments + - **gcloud**: Auto-complete for the gcloud CLI tool + - **ssh-agent**: Saves your SSH password so you only have to enter it once per session. + - **direnv**: A tool to load `.envrc` files when you `cd` into a directory. Great for loading environment variables. +- Installing **Spark**: Spark is a distributed data processing framework -echo "$(cat kubectl.sha256) kubectl" | sha256sum --check +**Data Engineering Challenges Repository** -sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl +The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -kubectl version --client -kubectl version --client --output=yaml -``` +Here is an image of how the Repository setup works: -### Install minikube +![](/images/repo_overview.png) -Minikube is a way to quickly spin up a local kubernetes cluster! +This allows you to work on challenges, but if we push any changes to the content, you can still access them! -https://minikube.sigs.k8s.io/docs/start/ +### Restart Virtual Machine -```bash -curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 -sudo install minikube-linux-amd64 /usr/local/bin/minikube -``` +Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). -### Test installation -To test that you can launch a cluster run: -```bash -minikube start -``` -you should see your cluster booting up : +To shutdown your VM, navigate to the GCP Compute Engine Instances [console page ๐Ÿ”—](https://console.cloud.google.com/compute/instances). -![](images/minikube_start.png) +Select your VM instance and click on the stop button: -Then to check the cluster run: -```bash -kubectl get po -A -``` -you should be able to see your cluster running! : +![](/images/gcp_vm_stop.png) -![](images/minikube_base.png) +Wait for a few minutes until the VM shows that it is completely off. You may need to refresh the page, the GCP Console doesn't dynamically update. -To tear it all down for now: +When the VM is completely off, turn it on again by selecting the check box next to your instance and clicking **START/RESUME**. Give it a minute to spin up, then connect via VS Code. -```bash -minikube delete --all -``` +## Check your Virtual Machine Setup -## Terraform +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. -Terraform is a tool for infrastructure as code (IAC) to define resources to create in the cloud! +โ— If any of these checks error out, raise a ticket with a teacher. -### Install terraform +#### Python -Install some basic requirements -```bash -sudo apt-get update && sudo apt-get install -y gnupg software-properties-common -``` +To test: -Terraform is not avaliable to apt by default so we need to make it avaliable! ```bash -wget -O- https://apt.releases.hashicorp.com/gpg | \ - gpg --dearmor | \ - sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null +python --version ``` -```bash -gpg --no-default-keyring \ - --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ - --fingerprint -``` +Should return: ```bash -echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ - https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ - sudo tee /etc/apt/sources.list.d/hashicorp.list +Python 3.12.8 ``` -Now we can install terraform directly with apt ๐Ÿ‘‡ -```bash -sudo apt update -sudo apt-get install terraform -``` +#### Pyenv -Verify the installation with: +To test: ```bash -terraform --version +pyenv versions ``` - - -## Spark - -Spark is a data processing framework: - -Move to your home directory: +Should return: ```bash -cd ~ + system +* 3.12.8 (set by /home//.pyenv/version) ``` -Download spark: +Note: There should be an `*` next to 3.12.8 -```bash -wget https://archive.apache.org/dist/spark/spark-3.5.3/spark-3.5.3-bin-hadoop3.tgz -``` +#### Pipx -Open the tarball: +To test: ```bash -mkdir -p ~/spark && tar -xzf spark-3.5.3-bin-hadoop3.tgz -C ~/spark +pipx list ``` -Set the environment variables needed by spark: +Should return something similar too: ```bash -echo "export SPARK_HOME=$HOME/spark/spark-3.5.3-bin-hadoop3" >> .zshrc -echo 'export PATH=$PATH:$SPARK_HOME/bin' >> .zshrc +venvs are in /home//.local/share/pipx/venvs +apps are exposed on your $PATH at /home//.local/bin +manual pages are exposed at /home//.local/share/man + package poetry 2.1.1, installed using Python 3.12.8 + - poetry + package ruff 0.11.0, installed using Python 3.12.8 + - ruff + package tldr 3.3.0, installed using Python 3.12.8 + - tldr + - man1/tldr.1 ``` -Let's restart our shell: - -```bash -exec zsh -``` +#### Data Engineering Challenges repo remotes -Test Spark works by running: +To test: ```bash -spark-shell +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v ``` -You should see an output similar to: +Should return: ```bash -Setting default log level to "WARN". -To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). -25/01/15 11:33:07 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable -Spark context Web UI available at http://de-vm-lrae-test.europe-north1-b.c.wagon-de.internal:4040 -Spark context available as 'sc' (master = local[*], app id = local-1736940788403). -Spark session available as 'spark'. -Welcome to - ____ __ - / __/__ ___ _____/ /__ - _\ \/ _ \/ _ `/ __/ '_/ - /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 - /_/ - -Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_432) -Type in expressions to have them evaluated. -Type :help for more information. - -scala> +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) ``` -Type `:quit` and hit enter to exit the spark-shell and continue. - - -## Python & Pip -Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python 3.12 ([3.12.8](https://www.python.org/downloads/release/python-3128/)). +#### Docker -Let's install pyenv to manage our python versions: +To test: ```bash -git clone https://github.com/pyenv/pyenv.git ~/.pyenv -source ~/.zprofile -exec zsh +docker run hello-world ``` -We'll also install a useful `pyenv` plugin called [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv). Although we will be using `poetry` for Python package and virtual environment management, `pyenv-virtualenv` is useful for controlling python versions locally. +Should return: ```bash -git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv -exec zsh -``` - -Now install Python 3.12.8: -```bash -pyenv install 3.12.8 -pyenv global 3.12.8 -``` -Now `python --version` should return `3.12.8` +Unable to find image 'hello-world:latest' locally +latest: Pulling from library/hello-world +e6590344b1a5: Pull complete +Digest: sha256:7e1a4e2d11e2ac7a8c3f768d4166c2defeb09d2a750b010412b6ea13de1efb19 +Status: Downloaded newer image for hello-world:latest +Hello from Docker! +This message shows that your installation appears to be working correctly. -## Pipx +To generate this message, Docker took the following steps: + 1. The Docker client contacted the Docker daemon. + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. + (amd64) + 3. The Docker daemon created a new container from that image which runs the + executable that produces the output you are currently reading. + 4. The Docker daemon streamed that output to the Docker client, which sent it + to your terminal. -Next we are going to install [pipx](https://pypa.github.io/pipx/) to install python packages we want globally available while still using virtual environments. +To try something more ambitious, you can run an Ubuntu container with: + $ docker run -it ubuntu bash -Let's upgrade `pip` first: +Share images, automate workflows, and more with a free Docker ID: + https://hub.docker.com/ -```bash -pip install --upgrade pip +For more examples and ideas, visit: + https://docs.docker.com/get-started/ ``` -And install `pipx`: +#### Kubernetes -```bash -python -m pip install --user pipx # --user so that each ubuntu user can have his own 'pipx' -python -m pipx ensurepath -exec zsh -``` - -Lets install a [tldr](https://github.com/tldr-pages/tldr) with pipx +We can start by testing `minikube`: ```bash -pipx install tldr +# Start +minikube start ``` -Now `tldr` should be globally available (for the current user), test it out with: +Should return: ```bash -tldr ls +๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) +โœจ Automatically selected the docker driver. Other choices: none, ssh +๐Ÿ“Œ Using Docker driver with root privileges +๐Ÿ‘ Starting "minikube" primary control-plane node in "minikube" cluster +๐Ÿšœ Pulling base image v0.0.46 ... +๐Ÿ’พ Downloading Kubernetes v1.32.0 preload ... + > gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 88.19 M + > preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 32.20 M +๐Ÿ”ฅ Creating docker container (CPUs=2, Memory=3900MB) ... +๐Ÿณ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ... + โ–ช Generating certificates and keys ... + โ–ช Booting up control plane ... + โ–ช Configuring RBAC rules ... +๐Ÿ”— Configuring bridge CNI (Container Networking Interface) ... +๐Ÿ”Ž Verifying Kubernetes components... + โ–ช Using image gcr.io/k8s-minikube/storage-provisioner:v5 +๐ŸŒŸ Enabled addons: storage-provisioner, default-storageclass +๐Ÿ„ Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default ``` -Much more readable than the classic `man ls` (although sometimes you will still need to delve into the man pages to get all of the details!) and it even has pages not included in man such as `tldr gh`: - -tldr - - -Lets add a few more packages we want globally available - -### black - -[black](https://black.readthedocs.io/en/stable/) for helping to format code +And then make sure the kubernetes CLI utility, `kubectl`, works with: ```bash -pipx install black +# Get pods +kubectl get po -A ``` -### Poetry - -[Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. - -Install Poetry running the following command in your VS Code terminal: +Should return something similar too: ```bash -pipx install poetry +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s +kube-system etcd-minikube 1/1 Running 0 78s +kube-system kube-apiserver-minikube 1/1 Running 0 76s +kube-system kube-controller-manager-minikube 1/1 Running 0 76s +kube-system kube-proxy-stk77 1/1 Running 0 72s +kube-system kube-scheduler-minikube 1/1 Running 0 76s +kube-system storage-provisioner 1/1 Running 1 (41s ago) 75s ``` -Then, let's update default poetry behavior so that virtual envs are always created where `poetry install` is run. -During the bootcamp, you'll see a `.venv` folder being created inside each challenge folder. +And because `minikube` is resource intensive, stop it for now with: ```bash -poetry config virtualenvs.in-project true -``` - -Finally, update your VScode settings to tell it that this `.venv` relative folder path will be your default interpreter! - -1. Open the Command Palette ( ๐ŸชŸ ctrl + shift + P / ๐ŸŽ cmd + shift + P ) -2. Search for: **Preference: Open Remote Settings (JSON)** - when you open your settings that should be two panels. -3. In the panel that opens on the **right side** search for the line: `python.defaultInterpreterPath` -4. Replace the value (probably `"~/.pyenv/shims/python"`) so that it looks like: - -```yml -"python.defaultInterpreterPath": ".venv/bin/python", -``` - -## Direnv - -[Direnv](https://direnv.net/) is a great utility that will look for `.envrc` files in your directories. When you `cd` into directories with a `.envrc` files, paths will automatically be updated. In our case, this will simplify our workflow and allow us to not have to worry about Poetry managed Python virtual environments. - -1. First, setup the *direnv hook* to your zsh shell so that direnv gets activated anytime a `.envrc` file exists in current working directory. - -```bash -code ~/.zshrc -``` - -```bash -plugins=(git gitfast ... pyenv ssh-agent direnv) # add `direnv` to the existing list of plugins +# Stop +minikube delete --all ``` -2. Second, let's configure what will happens anytime `.envrc` file is found +Should return: ```bash -code ~/.direnvrc +๐Ÿ”ฅ Deleting "minikube" in docker ... +๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... +๐Ÿ’€ Removed all traces of the "minikube" cluster. +๐Ÿ”ฅ Successfully deleted all profiles ``` -- Paste the following lines - ```bash - layout_poetry() { - if [[ ! -f pyproject.toml ]]; then - log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.' - exit 2 - fi - # create venv if it doesn't exist - poetry run true - export VIRTUAL_ENV=$(poetry env info --path) - export POETRY_ACTIVE=1 - PATH_add "$VIRTUAL_ENV/bin" - } - ``` -- Save and close the file +#### Terraform -๐Ÿ˜Ž Now, **anytime you `cd` into a challenge folder which contains a `.envrc` file which contains `layout_poetry()` command inside, the function will get executed and your virtual env will switch to the poetry one that is defined by the `pyproject.toml` !** -- No need to prefix all commands with `poetry run `, but simply `` -- Each challenge will have its own virtual env, and it will be seamless for you to switch between challenges/envs - - -## Let's Make! - -Lets clone the challenges onto your **virtual machine** +To test: ```bash -export GITHUB_USERNAME=`gh api user | jq -r '.login'` -echo $GITHUB_USERNAME +terraform --version ``` -Then: +Should return: ```bash -mkdir -p ~/code/$GITHUB_USERNAME && cd $_ -gh repo fork lewagon/data-engineering-challenges --clone +Terraform v1.11.2 +on linux_amd64 ``` -Our setup will look a bit like this: - - - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! +#### Spark -Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! +To test: ```bash -cd data-engineering-challenges -git remote -v -# origin git@github.com:your_github_username/data-engineering-challenges.git (fetch) -# origin git@github.com:your_github_username/data-engineering-challenges.git (push) -# upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -# upstream git@github.com:lewagon/data-engineering-challenges.git (push) +spark-shell ``` -From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: +Should take you into the spark shell that looks like: -- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) -- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) -- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder +```bash +Setting default log level to "WARN". +To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). +25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable +Spark context Web UI available at http://lw-de-vm.europe-north1-b.c.wagon-de.internal:4040 +Spark context available as 'sc' (master = local[*], app id = local-1742288096829). +Spark session available as 'spark'. +Welcome to + ____ __ + / __/__ ___ _____/ /__ + _\ \/ _ \/ _ `/ __/ '_/ + /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 + /_/ -Let's make! +Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_442) +Type in expressions to have them evaluated. +Type :help for more information. -```bash -make install +scala> ``` -This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. +Type `:quit` and hit enter to exit the spark-shell and continue. -โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ +That's everything for now! diff --git a/macOS.md b/macOS.md index 8e63d2b..8ef427d 100644 --- a/macOS.md +++ b/macOS.md @@ -6,6 +6,42 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: +This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! +- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! + +## Part 1: Setup your local computer + +In this section you'll setup your local computer and create some accounts. It will include things like: +1. Install some communication tools: Zoom, Slack +2. Create some accounts: Github, Google Cloud Platform (GCP) +3. Install Visual Studio Code (VS Code) +4. Install and authentication the GCP command line tool: `gcloud`. +5. Install **terraform** on your local computer. +6. Create your virtual machine with **terraform** and connect to it with **VS Code**! + +## Part 2: Configure your Virtual Machine Part 1 + +All parts of this section happen on your virtual machine. + +This section includes: +1. Authenticate your virtual machine with `gcloud` +2. Download and run an **ansible** playbook to partially configure your virtual machine. +3. Login to the Github command line tool on your virtual machine +4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! + +## Part 3: Configure your Virtual Machine Part 2 + +All parts of this section happen on your virtual machine. + +In this section you will: +1. Download and run a second **ansible** playbook for some more fine tuning. +2. Test your set up to make sure that everything has installed correctly. +3. Create some python environments. + + +Don't worry, we'll go into more detail in each of the individual sections. + Let's start :rocket: @@ -89,62 +125,15 @@ Have you signed up to GitHub? If not, [do it right away](https://github.com/join :point_right: **[Enable Two-Factor Authentication (2FA)](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication#configuring-two-factor-authentication-using-text-messages)**. GitHub will send you text messages with a code when you try to log in. This is important for security and also will soon be required in order to contribute code on GitHub. -## SSH key +## Chrome - your browser -We want to safely communicate with your virtual machine using [SSH protocol](https://en.wikipedia.org/wiki/Secure_Shell). We need to generate a SSH key to authenticate. +Install the Google Chrome browser if you haven't got it already and set it as a __default browser__. -- Open your terminal +Follow the steps for your system from this link :point_right: [Install Google Chrome](https://support.google.com/chrome/answer/95346?co=GENIE.Platform%3DDesktop&hl=en-GB) -
- ๐Ÿ’ก Windows tip - -We highly recommend installing [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=fr-fr&gl=FR) from the Windows Store (installed on Windows 11 by default) to perform this operation -
- -- Create a SSH key - -
- Windows +__Why Chrome?__ -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen.exe -t ed25519 -C "your_email@example.com" -``` -
- -
- MacOS & Linux - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -C "your_email@example.com" -``` -
- - -You should get the following message: `> Generating public/private algorithm key pair.` -- When you are prompted `> Enter a file in which to save the key`, press Enter -- You should be asked to `Enter a passphrase` - this is optional if you want additional security. To continue without a passphrase press enter without typing anything when asked to enter a passphrase. - -โ„น๏ธ Don't worry if nothing prompt when you type, that is perfectly normal for security reasons. - -- You should be asked to `Enter same passphrase again`, do it. - -**โ—๏ธ You must remember this passphrase.** - -
- โ—๏ธ /home/your_username/.ssh/id_ed25519 already exists. -If you receive this message, you may already have an SSH Key with the same name (if you are a Le Wagon Alumni or are using SSH Authentication with Github). - -To create a separate SSH key to exclusively use for this bootcamp use the following: - -```bash -# replace "your_email@example.com" with your GCP account email -ssh-keygen -t ed25519 -f ~/.ssh/de-bootcamp -C "your_email@example.com" -``` - -Your new SSH Key will be named `de-bootcamp`. Make sure to remember it for later! -
+We recommend to use it as your default browser as it's most compatible with testing or running your code, as well as working with Google Cloud Platform. Another alternative is Firefox, however we don't recommend using other tools like Opera, Internet Explorer or Safari. ## Google Cloud Platform setup @@ -287,85 +276,75 @@ Go to your project [APIs dashboard](https://console.cloud.google.com/apis/dashbo - Compute Engine is now enabled on your project -## Virtual Machine (VM) - -**๐Ÿ‘Œ Note: Skip to the next section if you already have a VM set up** - -_Note: The following section requires you already have a [Google Cloud Platform](https://cloud.google.com/) account associated with an active [Billing account](https://console.cloud.google.com/billing)._ +## Homebrew +### 1. Install: +On Mac, you need to install [Homebrew](http://brew.sh/) which is a Package Manager. +It will be used as soon as we need to install some software. +To do so, open your Terminal and run: -- Go to console.cloud.google.com > > Compute Engine > VM instances > Create instance -- Name it `lewagon-data-eng-vm-`, replace `` with your own, e.g. `krokrob` -- Region `europe-west1`, choose the closest one among the [available regions](https://cloud.google.com/compute/docs/regions-zones#available) - - gcloud-console-vm-create-instance -- In the section `Machine configuration` under the sub-heading `Machine type` -- Select General purpose > PRESET > e2-standard-4 - - gcloud-console-vm-e2-standard4 -- Boot disk > Change - - Operating system > Ubuntu - - Version > Ubuntu 22.04 LTS x86/64 - - Boot disk type > Balanced persistent disk - - Size > upgrade to 150GB - - gcloud-console-vm-ubunt -- Open `Networking, Disks, ...` under `Advanced options` -- Open `Networking` +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` - gcloud-console-vm-networking -- Go to `Network interfaces` and click on `default default (...)` with a downward arrow on the right. +This will ask for your confirmation (hit `Enter`) and your **macOS user account password** (the one you use to [log in](https://support.apple.com/en-gb/HT202860) when you reboot your Macbook). +:warning: When typing a password in the Terminal, you will **not** get a visual feedback (something like `*****`), this is **normal**!! Type the password and confirm by typing `Enter`. - gcloud-console-vm-network-interfaces -- This opened a box `Edit network interface` -- Go to the dropdown `External IPv4 address`, click on it, click on `RESERVE STATIC EXTERNAL IP ADDRESS` +
+ ๐Ÿ›  If you get a Error: Not a valid ref: refs/remotes/origin/master error - gcloud-console-vm-create-static-ip -- Give it a name, like "lewagon-data-eng-vm-ip-" (replace `` with your own) and description "Le Wagon - Data Engineering VM IP". This will take a few seconds. - gcloud-console-reserve-static-ip +The full error would be: -- You will now have a public IP associated with your account, and later to your VM instance. Click on `Done` at the bottom of the section `Edit network interface` you were in. +``` bash +Error: Not a valid ref: refs/remotes/origin/master : +fatal: ambiguous argument 'refs/remotes/origin/master': unknown revision or path not in the working tree. +``` - gcloud-console-new-external-ip +Run the following commands to solve it: -### Public SSH key -- Open the `Security` section +``` bash +rm -fr $(brew --repo homebrew/core) # because you can't `brew untap homebrew/core` +brew tap homebrew/core +``` - gcloud-console-vm-security -- Open the `Manage access` subsection +
- gcloud-console-manage-access -- Go to `Add manually generated SSH keys` and click `Add item` +If you already have Homebrew, it will tell you so, that's fine, go on. - gcloud-console-add-manual-ssh-key -- In your terminal display your public SSH key: - - Windows: navigate to where you created your SSH key and open `id_ed25519.pub` +### 2. Make sure you are on the latest version: - - Mac/Linux users can use: - ```bash - cat ~/.ssh/id_ed25519.pub - # OR cat ~/.ssh/de-bootcamp.pub if you created a unique key - ``` -- Copy your public SSH key and paste it: +```bash +brew update +``` - gcloud-console-add-ssh-key-pub -- On the right hand side you should see +
+ ๐Ÿ›  If you get a /usr/local must be writable error - gcloud-console-vm-price-month -- You should be good to go and click `CREATE` at the bottom +Just run this: - gcloud-console-vm-create -- It will take a few minutes for your virtual machine (VM) to be created. Your instance will show up like below when ready, with a green circled tick, named `lewagon-data-eng-vm-krokrob` (`krokrob` being replaced by your GitHub username). +``` bash +sudo chown -R $USER:admin /usr/local +brew update +``` - gcloud-console-vm-instance-running -- Click on your instance +
- gcloud-console-vm-running -- Go down to the section `SSH keys`, and write down your username (you need it for the next section) +### 3. Then install some useful software: - gcloud-console-vm-username +Proceed running the following in the terminal (you can copy / paste all the lines at once). -Congrats, your virtual machine is up and running, it is time to connect it with VS Code! +```bash +brew upgrade git || brew install git +brew upgrade gh || brew install gh +brew upgrade wget || brew install wget +brew upgrade imagemagick || brew install imagemagick +brew upgrade jq || brew install jq +brew upgrade openssl || brew install openssl +brew upgrade tree || brew install tree +brew upgrade ncdu || brew install ncdu +brew upgrade xz || brew install xz +brew upgrade readline || brew install readline +``` ## Visual Studio Code @@ -396,170 +375,342 @@ We need to connect VS Code to a virtual machine in the cloud so you will only wo That's the only extension you should install on your _local_ machine, we will install additional VS Code extensions on your _virtual machine_. -### Virtual Machine connection -- Open VS Code > Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` +## Google Cloud CLI + +The `gcloud` Command Line Interface (CLI) is used to communicate with Google Cloud Platform services through your terminal. + +### Install gcloud -vscode-connect-to-host +Install with `brew`: -- Click on `Add a new host` -- Type `ssh -i @`, for instance, my username is `somedude`, my private SSH key is located at `~/.ssh/id_rsa` on my local computer, my VM has a public IP of `34.77.50.76`: I'll type `ssh -i ~/.ssh/id_rsa somedude@34.77.50.76` +```bash +brew install --cask google-cloud-sdk +``` -vscode-ssh-connection-command +Then you can: +```bash +$(brew --prefix)/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/install.sh +``` -- When prompted to `Select SSH configuration file to update`, pick the one in your home directory, under the `.ssh` folder, `~/.ssh/config` basically. Usually VS Code will pick automatically the best option, so their default should work. +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#) -vscode-add-host-ssh-config +To test your install, run the following in your terminal: -- You should get a pop-up on the bottom right notifying you the host has been added +```bash +gcloud --version +``` -vscode-host-added -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Remote-SSH: Connect to Host...` > Pick your VM IP address +### Authenticate gcloud -vscode-add-new-host +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. -- The first time, VSCode might ask you for a security permission like below, say yes / continue. +To authenticate `gcloud`, run: -vscode-remote-connection-confirm +```bash +gcloud auth login +``` -- Open again the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) > Type `Terminal: Create New Terminal (in active workspace)` > You now have a Bash terminal in your virtual machine! +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V -vscode-command-palette-new-terminal -
-vscode-terminal +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. -- Still on your *local* computer, lets create a more readable version of your machine to connect to! +To set your project, replace `` with your GCP Project ID and run: ```bash -code ~/.ssh/config +gcloud config set project ``` -You should see something like the following: +To confirm your setup, run: ```bash -Host - HostName - IdentityFile - User +gcloud config list ``` -You can now change Host to whatever you would like to see as the name of your connection or in terminal with `ssh `! -โ—๏ธ It is important that the `Host` alias does not contain any whitespaces โ—๏ธ +You should get an output similar to: ```bash -# For instance -Host "de-bootcamp-vm" - HostName 34.77.50.76 # replace with your VM's public IP address - IdentityFile - User +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] ``` -**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS code for instance) +## Terraform + +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! + +You can use `brew` to install terraform. In your terminal, run: + +```bash +brew tap hashicorp/tap +brew install hashicorp/tap/terraform +``` + +Verify the installation with: -## VS Code Extensions +```bash +terraform --version +``` -Let's install some useful extensions to VS Code. -- Open your VS Code instance and make sure you're connected to the remote server. At the bottom left, you'll see: +## Provisioning your Virtual Machine with Terraform -vscode-ssh +We're almost at the point of creating your Virtual Machine. -- Open the VS Code terminal (`CMD` + `` ` `` or `CTRL` + `` ` ``) then run the following commands: +The specifications of the machine you'll use for the bootcamp are: +- Operation System: Ubuntu 22.04 LTS +- CPU: 4 Virtual CPU cores +- RAM: 16 GB +- Storage: 100 GB +- Network: Static External IP address + +### Cost ๐Ÿ’ธ + +Creating and running a Virtual Machine on Google Cloud Platform costs money. + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). + +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! + +You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. + +### Download terraform files + +We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. + +First we'll create a folder and download the terraform files with: + +```bash +mkdir -p ~/wagon-de-bootcamp +curl -L -o ~/wagon-de-bootcamp/main.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf +curl -L -o ~/wagon-de-bootcamp/provider.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf +curl -L -o ~/wagon-de-bootcamp/variables.tf https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf +curl -L -o ~/wagon-de-bootcamp/terraform.tfvars https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars +curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl +``` + + +### Set variables + +Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: + +```bash +project_id = "" +region = "" +zone = "" +instance_name = "" +instance_user = "" +``` + +We'll need to change some values in this file. Here's were you can find the required values: +- **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). +- **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. +- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **instance_user:** in your terminal, run `whoami` and hit enter. + +After completing this file, it should look similar to: + +```bash +project_id = "wagon-bootcamp" +region = "europe-west1" +zone = "europe-west1-b" +instance_name = "lw-de-vm-tswift" +instance_user = "taylorswift" # result of `whoami` +``` + +Make sure to save the `terraform.tfvars` file and then run: + +```bash +cd ~/wagon-de-bootcamp + +terraform init + +terraform plan +``` + +And check the output, if you have any errors, raise a ticket with a teacher. + +If everything was successful, create your VM with: + +```bash +terraform apply -auto-approve +``` + +And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. + + +### Virtual Machine connection + +We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. + +To create the VS Code SSH configuration, run the following in your terminal: + +```bash +gcloud compute config-ssh +``` + +You should get an output similar to: + +```bash +You should now be able to use ssh/scp with your instances. +For example, try running: + + $ ssh lw-de-vm-tswift.europe-west1-b.wagon-bootcamp +# $ ssh lw-de-vm-.. +``` + +To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: + +![](/images/vscode_remote_highlight.png) + +It should bring up a menu: + +![](/images/vscode_remote_menu.png) + +Click on the name of your Virtual Machine: + +![](/images/vscode_remote_hosts.png) + +A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. + +![](/images/vscode_remote_fingerprint.png) + +And you are connected! It should look similar too: + +![](/images/vscode_remote_connected.png) + +Notice the connection in the very bottom-left corner of your VS Code window. It should have the Connection type (SSH), and the name of the host you are connected to. + +**The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) + + +## Google Authentication + +Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. + +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your Application Default Credentials, in your terminal run: ```bash -code --install-extension ms-vscode.sublime-keybindings -code --install-extension emmanuelbeziat.vscode-great-icons -code --install-extension ms-python.python -code --install-extension KevinRose.vsc-python-indent -code --install-extension ms-python.vscode-pylance -code --install-extension redhat.vscode-yaml -code --install-extension ms-azuretools.vscode-docker -code --install-extension tamasfe.even-better-toml +gcloud auth application-default login ``` -Here is a list of the extensions you are installing: -- [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) -- [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) -- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) -- [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) -- [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) -- [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) -- [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) -- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +### Authenticate gcloud + +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. + +To authenticate `gcloud`, run: + +```bash +gcloud auth login +``` -## Command line tools +And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V -### Zsh & Git +You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. -Instead of using the default `bash` [shell](https://en.wikipedia.org/wiki/Shell_(computing)), we will use `zsh`. +To set your project, replace `` with your GCP Project ID and run: -We will also use [`git`](https://git-scm.com/), a command line software used for version control. +```bash +gcloud config set project +``` -Let's install them, along with other useful tools: -- Open an **VS Code terminal** connected to your VM -- Copy and paste the following commands: +To confirm your setup, run: ```bash -sudo apt update -sudo apt install -y vim tmux tree git ca-certificates curl jq unzip zsh \ -apt-transport-https gnupg software-properties-common direnv sqlite3 make \ -postgresql postgresql-contrib build-essential libssl-dev zlib1g-dev \ -libbz2-dev libreadline-dev libsqlite3-dev wget llvm \ -libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \ -gcc default-mysql-server default-libmysqlclient-dev libpython3-dev openjdk-8-jdk-headless +gcloud config list ``` -These commands might ask for your password, if they do: type it in. +You should get an output similar to: + +```bash +[core] +account = taylorswift@domain.com # Should be your GCP email +disable_usage_reporting = True +project = my-gcp-project # Should be your GCP Project ID + +Your active configuration is: [default] +``` -:warning: When you type your password, nothing will show up on the screen, **that's normal**. This is a security feature to mask not only your password as a whole but also its length. Just type in your password and when you're done, press `Enter`. -### GitHub CLI installation +## VM configuration with Ansible -Let's now install [GitHub official CLI](https://cli.github.com) (Command Line Interface). It's a software used to interact with your GitHub account via the command line. +We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. -In your terminal, copy-paste the following commands and type in your password if asked: +Let's start by confirming that ansible is installed. In your terminal run: ```bash -curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null -sudo apt update -sudo apt install -y gh +ansible --version ``` -To check that `gh` has been successfully installed on your machine, you can run: +You should get an output similar to (some version numbers might change, that's fine): ```bash -gh --version +ansible [core 2.17.9] + config file = /etc/ansible/ansible.cfg + configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /usr/lib/python3/dist-packages/ansible + ansible collection location = /home/tswift/.ansible/collections:/usr/share/ansible/collections + executable location = /usr/bin/ansible + python version = 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3) + jinja version = 3.1.2 + libyaml = True ``` -:heavy_check_mark: If you see `gh version X.Y.Z (YYYY-MM-DD)`, you're good to go :+1: +If not, raise a ticket with a teacher. -:x: Otherwise, please **contact a teacher** +### Ansible Playbook 1 +If everything looks ok, lets create a folder and download the ansible files: -## Oh-my-zsh +```bash +mkdir -p ~/vm-ansible-setup/playbooks -Let's install the `zsh` plugin [Oh My Zsh](https://ohmyz.sh/). +curl -L -o ~/vm-ansible-setup/ansible.cfg https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/ansible.cfg +curl -L -o ~/vm-ansible-setup/hosts https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/hosts +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part1.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part1.yml +``` -In a terminal execute the following command: +And run with: ```bash -sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part1.yml ``` -If asked "Do you want to change your default shell to zsh?", press `Y` +And the playbook should start running! + +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. + +### What is the playbook installing? -At the end your terminal should look like this: +This playbook is installing a few things, while the playbook is running, let's go through them: +- Updating system packages. Ubuntu uses the `APT` package manager. +- Changing the default shell from **bash** to **zsh**, a more customizable shell that is extensible and looks great! +- Installing the **Oh-My-ZSH** plugin for the **zsh** shell. We'll use it a bit later to add some quality of life plugins and extensions for `zsh`. +- Installing **Docker** on your Virtual Machine. Docker is an open platform for developing, shipping, and running applications. You will use it throughout the bootcamp +- Installing some **Kubernetes (k8s)** tooling: Kubernetes is a system designed to for auto-scaling containerized applications. + - Installing **kubectl**: `kubectl` is the CLI tool for interacting with kubernetes clusters. + - Installing **minikube**: Minikube is a way to quickly spin up a local kubernetes cluster. Great for developing! +- Installing **terraform**: we've already installed it once, but we need to install it on our VM! **Terraform** is an Infrastructure as Code (IaC) tool. +- Install the **GitHub CLI**: the CLI tool that we'll use to interact with your GitHub account directly from the terminal. -![Ubuntu terminal with OhMyZsh](https://github.com/lewagon/setup/blob/master/images/oh_my_zsh.png) +The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -:heavy_check_mark: If it does, you can continue :+1: +Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: -:x: Otherwise, please **ask for a teacher** +![](/images/vscode_after_ansible1.png) ## GitHub CLI @@ -614,120 +765,6 @@ gh auth status :x: If not, **contact a teacher**. -## Google Cloud CLI - -Install the `gcloud` CLI to communicate with [Google Cloud Platform](https://cloud.google.com/) through your terminal: -```bash -echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list -sudo apt-get install apt-transport-https ca-certificates gnupg -curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - -sudo apt-get update && sudo apt-get install google-cloud-sdk -sudo apt-get install google-cloud-sdk-app-engine-python -``` -๐Ÿ‘‰ [Install documentation](https://cloud.google.com/sdk/docs/install#deb) - -### Create a service account key ๐Ÿ”‘ - -**๐Ÿ‘Œ Note: Skip to the next section if you already have a service account key** - -Now that you have created a `GCP account` and a `project` (identified by its `PROJECT_ID`), we are going to configure the actions (API calls) that you want to allow your code to perform. - -
- ๐Ÿค” Why do we need a service account key ? - - - You have created a `GCP account` linked to your credit card. Your account will be billed according to your usage of the ressources of the **Google Cloud Platform**. The billing will occur if you consume anything once the free trial is over, or if you exceed the amount of spending allowed during the free trial. - - In your `GCP account`, you have created a single `GCP project`, identified by its `PROJECT_ID`. The `GCP projects` allow you to organize and monitor more precisely how you consume the **GCP** ressources. For the purpose of the bootcamp, we are only going to create a single project. - - Now, we need a way to tell which ressources within a `GCP project` our code will be allowed to consume. Our code consumes GCP ressources through API calls. - - Since API calls are not free, it is important to define with caution how our code will be allowed to use them. During the bootcamp this will not be an issue and we are going to allow our code to use all the API of **GCP** without any restrictions. - - In the same way that there may be several projects associated with a GCP account, a project may be composed of several services (any bundle of code, whatever its form factor, that requires the usage of GCP API calls in order to fulfill its purpose). - - GCP requires that the services of the projects using API calls are registered on the platform and their credentials configured through the access granted to a `service account`. - - For the moment we will only need to use a single service and will create the corresponding `service account`. -
- -Since the [service account](https://cloud.google.com/iam/docs/service-accounts) is what identifies your application (and therefore your GCP billing account and ultimately your credit card), you are going to want to be cautious with the next steps. - -โš ๏ธ **Do not share you service account json file ๐Ÿ”‘** โš ๏ธ Do not store it on your desktop, do not store it in your git codebase (even if your git repository is private), do not let it by the coffee machine, do not send it as a tweet. - -- Go to the [service accounts page](https://console.cloud.google.com/apis/credentials/serviceaccountkey) -- Select your project in the list of recent projects if asked to -- Create a service account: - - Click on **CREATE SERVICE ACCOUNT**: - - Give a `Service account name` to that account - - Click on **CREATE AND CONTINUE** - - Click on **Select a role** and choose `Quick access/Basic` then **Owner**, which gives full access to all ressources - - Click on **CONTINUE** - - Click on **DONE** -- Download the service account json file ๐Ÿ”‘: - - Click on the newly created service account - - Click on **KEYS** - - Click on **ADD KEY** then **Create new key** - - Select **JSON** and click on **CREATE** - -![](images/gcp_create_key.png) - -The browser has now saved the service account json file ๐Ÿ”‘ in your downloads directory (it is named according to your service account name, something like `le-wagon-data-123456789abc.json`) - - -### Configure Cloud sdk - -- Open the service account json file with any text editor and copy the key - ``` - # It looks like: - { - "type": "service_account", - "project_id": "kevin-bootcamp", - "private_key_id": "1234567890", - "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n", - "client_email": "bootcamp@kevin-bootcamp.iam.gserviceaccount.com", - "client_id": "1234567890", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/bootcamp%40kevin-bootcamp.iam.gserviceaccount.com" - } - ``` -- **on your Virtual Machine**, create a `~/.gcp_keys` directory, then create a json file in it: - ``` bash - mkdir ~/.gcp_keys - touch ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` -- Open the json file then store the service account json file pasting the key: - ```bash - code ~/.gcp_keys/le-wagon-de-bootcamp.json - ``` - ![service account json key](images/service_account_json_key.png) - - โ—๏ธDon't forget to **save** the file with `CMD` + `s` or `CTRL` + `s` - -- Authenticate the `gcloud` CLI with the google account you used for GCP - ```bash - # Replace service_account_name@project_id.iam.gserviceaccount.com with your own - SERVICE_ACCOUNT_EMAIL=service_account_name@project_id.iam.gserviceaccount.com - KEY_FILE=$HOME/.gcp_keys/le-wagon-de-bootcamp.json - gcloud auth activate-service-account $SERVICE_ACCOUNT_EMAIL --key-file=$KEY_FILE - ``` -- List your active account and check your email address you used for GCP is present - ```bash - gcloud auth list - ``` -- Set your current project - ```bash - # Replace `PROJECT_ID` with the `ID` of your project, e.g. `wagon-bootcamp-123456` - gcloud config set project PROJECT_ID - ``` -- List your active account and current project and check your project is present - ```bash - gcloud config list - ``` - - ## Dotfiles Let's pimp your zsh and and vscode by installing lewagon recommanded dotfiles **on your Virtual Machine** @@ -874,491 +911,327 @@ you don't want your email to appear in public repositories you may contribute to -### zsh default terminal +## VM configuration with Ansible - Part 2 -Set `zsh` as your default VS Code terminal. +### Ansible Playbook 2 -- Open terminal default profile settings +We'll be using a second **ansible** playbook to further configure your Virtual Machine. - Terminal profile settings -- Select `zsh /usr/bin/zsh` - - Terminal zsh profile - - -## Disable SSH passphrase prompt - -You don't want to be asked for your passphrase every time you communicate with a distant repository. So, you need to add the plugin `ssh-agent` to `oh my zsh`: - -First, open the `.zshrc` file: +Start by downloading the ansible playbook: ```bash -code ~/.zshrc +curl -L -o ~/vm-ansible-setup/playbooks/setup_vm_part2.yml https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/vm-ansible-setup/playbooks/setup_vm_part2.yml ``` -Then: -- Spot the line starting with `plugins=` -- Add `ssh-agent` at the end of the plugins list - -:heavy_check_mark: Save the `.zshrc` file with `Ctrl` + `S` and close your text editor. - - -## Docker ๐Ÿ‹ - -Docker is an open platform for developing, shipping, and running applications. - -### Install Docker and Docker Compose - -Setup the dock apt repo +And run with: ```bash -sudo install -m 0755 -d /etc/apt/keyrings - -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg - -sudo chmod a+r /etc/apt/keyrings/docker.gpg +cd ~/vm-ansible-setup +ansible-playbook playbooks/setup_vm_part2.yml ``` -```bash -echo \ - "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ - "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null -``` +And the playbook should start running! -Install the right packages +โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. -``` -sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -``` +### What is the playbook installing? -Finally give your user permission to use `docker` +This playbook is installing and configuring a things, while the playbook is running, let's go through them: -```bash -sudo groupadd docker -sudo usermod -aG docker $USER -newgrp docker -``` +**Python and Poetry** -Run `docker run hello-world`, you should see something like: +Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python [3.12.8](https://www.python.org/downloads/release/python-3128/) -
- โ—๏ธ Permission denied while trying to connect to the Docker daemon socket. โ—๏ธ +- Install **pyenv** and **pyenv-virtualenv**. We'll use **pyenv** to manage the Python versions installed on the VM +- Install Python 3.12.8 with pyenv +- Install **pipx**: [Pipx](https://pipx.pypa.io/stable/) is used to install python packages we want _globally_ available while still using virtual environments, like Poetry! +- Installing a few global python packages with **pipx**: + - **Poetry:** [Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. + - **Ruff:** [Ruff](https://docs.astral.sh/ruff/) Is used to format and lint Python code. + - **tldr:** [tldr](https://github.com/tldr-pages/tldr) has much more readable version of `man` pages. Useful for quickly finding out how a program works. -If you receive an error similar to the one below, navigate to the [GCP Compute Engine Console](https://console.cloud.google.com/compute/instances) and shut down your VM by selecting the tick box next to your VM instance and clicking STOP (closing and reopening VSCode is not enough). +**VS Code Configuration** -![](images/docker_permission_denied_socket.png) +- Installing some **VS Code** extensions, but only on your VM. Here's a list of the extensions that are being installed: + - [Sublime Text Keymap and Settings Importer](https://marketplace.visualstudio.com/items?itemName=ms-vscode.sublime-keybindings) + - [VSCode Great Icons](https://marketplace.visualstudio.com/items?itemName=emmanuelbeziat.vscode-great-icons) + - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + - [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) + - [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) + - [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) + - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + - [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) +- Update the VS Code Python Interpreter path. -It will take a few minutes for your VM to turn off. Once it's fully off, turn your VM on again by checking the box next to the VM instance and clicking START. Give the VM a few minutes to fully start up and connect through VSCode. Once connected try `docker run hello-world` again. If you don't get an output similar to the below image, raise a ticket with a teacher. -
+**Shell and System Configuration** -![](images/docker_hello.png) +- Create the **direnv** poetry function. The same one from the lecture! This makes it easier to work with poetry. +- Adding some **Oh-My-ZSH** Plugins: by modifying your `.zshrc` file. Here's a list of the extra plugins: + - **pyenv**: Auto-complete for pyenv, a tool used to manage python virtual environments + - **gcloud**: Auto-complete for the gcloud CLI tool + - **ssh-agent**: Saves your SSH password so you only have to enter it once per session. + - **direnv**: A tool to load `.envrc` files when you `cd` into a directory. Great for loading environment variables. +- Installing **Spark**: Spark is a distributed data processing framework -### Enable Artifact Registry API +**Data Engineering Challenges Repository** -**๐Ÿ‘Œ Note: Skip to the next section if you already have an Artifact Registry repository** +The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -[Artifact Registry](https://cloud.google.com/artifact-registry) is a GCP service you will use to store artifacts such as Docker images. The storage units are called repositories. +Here is an image of how the Repository setup works: -- Enable the service within your project using the `gcloud` CLI: - ```bash - gcloud services enable artifactregistry.googleapis.com - ``` -- Create a new Docker repository: - ```bash - # Set the repository name - REPOSITORY=docker-hub - # Set the location of the repository. Available locations: gcloud artifacts locations list - LOCATION=europe-west1 - gcloud artifacts repositories create $REPOSITORY \ - --repository-format=docker \ - --location=$LOCATION \ - --description="Docker images storage" - ``` +![](/images/repo_overview.png) -### Gcloud authentication for Docker +This allows you to work on challenges, but if we push any changes to the content, you can still access them! -You need to grant Docker access to push artifacts to (and pull from) your repository. There are different authentication methods, [gcloud credentials helper](https://cloud.google.com/artifact-registry/docs/docker/authentication#gcloud-helper) being the easiest. +### Restart Virtual Machine -- Define the repository hostname matching the repository `$LOCATION`: - ```bash - # If $LOCATION is "europe-west1" - HOSTNAME=europe-west1-docker.pkg.dev - ``` -- Configure gcloud credentials helper: - ```bash - gcloud auth configure-docker $HOSTNAME - ``` -- Type `y` to accept the configuration -- Check your credentials helper is set: - ```bash - cat ~/.docker/config.json - ``` - You should get: - ```bash - { - "credHelpers": { - "europe-west1-docker.pkg.dev": "gcloud" - } - }% - ``` +Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). +To shutdown your VM, navigate to the GCP Compute Engine Instances [console page ๐Ÿ”—](https://console.cloud.google.com/compute/instances). -## Kubernetes -Kubernetes (K8s) is a system designed to make deploying auto-scaling containerized applications easily. +Select your VM instance and click on the stop button: -### Install kubectl -Kubectl is the cli for interacting with k8s! +![](/images/gcp_vm_stop.png) -https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ +Wait for a few minutes until the VM shows that it is completely off. You may need to refresh the page, the GCP Console doesn't dynamically update. -```bash -curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256" +When the VM is completely off, turn it on again by selecting the check box next to your instance and clicking **START/RESUME**. Give it a minute to spin up, then connect via VS Code. -echo "$(cat kubectl.sha256) kubectl" | sha256sum --check -sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl - -kubectl version --client -kubectl version --client --output=yaml -``` +## Check your Virtual Machine Setup -### Install minikube +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. -Minikube is a way to quickly spin up a local kubernetes cluster! +โ— If any of these checks error out, raise a ticket with a teacher. -https://minikube.sigs.k8s.io/docs/start/ +#### Python -```bash -curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 -sudo install minikube-linux-amd64 /usr/local/bin/minikube -``` +To test: -### Test installation -To test that you can launch a cluster run: ```bash -minikube start +python --version ``` -you should see your cluster booting up : -![](images/minikube_start.png) +Should return: -Then to check the cluster run: ```bash -kubectl get po -A +Python 3.12.8 ``` -you should be able to see your cluster running! : -![](images/minikube_base.png) +#### Pyenv -To tear it all down for now: +To test: ```bash -minikube delete --all +pyenv versions ``` +Should return: -## Terraform - -Terraform is a tool for infrastructure as code (IAC) to define resources to create in the cloud! - -### Install terraform - -Install some basic requirements ```bash -sudo apt-get update && sudo apt-get install -y gnupg software-properties-common + system +* 3.12.8 (set by /home//.pyenv/version) ``` -Terraform is not avaliable to apt by default so we need to make it avaliable! -```bash -wget -O- https://apt.releases.hashicorp.com/gpg | \ - gpg --dearmor | \ - sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null -``` +Note: There should be an `*` next to 3.12.8 -```bash -gpg --no-default-keyring \ - --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ - --fingerprint -``` +#### Pipx -```bash -echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ - https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ - sudo tee /etc/apt/sources.list.d/hashicorp.list -``` +To test: -Now we can install terraform directly with apt ๐Ÿ‘‡ ```bash -sudo apt update -sudo apt-get install terraform +pipx list ``` -Verify the installation with: +Should return something similar too: ```bash -terraform --version +venvs are in /home//.local/share/pipx/venvs +apps are exposed on your $PATH at /home//.local/bin +manual pages are exposed at /home//.local/share/man + package poetry 2.1.1, installed using Python 3.12.8 + - poetry + package ruff 0.11.0, installed using Python 3.12.8 + - ruff + package tldr 3.3.0, installed using Python 3.12.8 + - tldr + - man1/tldr.1 ``` +#### Data Engineering Challenges repo remotes - -## Spark - -Spark is a data processing framework: - -Move to your home directory: +To test: ```bash -cd ~ +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v ``` -Download spark: +Should return: ```bash -wget https://archive.apache.org/dist/spark/spark-3.5.3/spark-3.5.3-bin-hadoop3.tgz +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) ``` -Open the tarball: +#### Docker -```bash -mkdir -p ~/spark && tar -xzf spark-3.5.3-bin-hadoop3.tgz -C ~/spark -``` - -Set the environment variables needed by spark: +To test: ```bash -echo "export SPARK_HOME=$HOME/spark/spark-3.5.3-bin-hadoop3" >> .zshrc -echo 'export PATH=$PATH:$SPARK_HOME/bin' >> .zshrc +docker run hello-world ``` -Let's restart our shell: +Should return: ```bash -exec zsh -``` +Unable to find image 'hello-world:latest' locally +latest: Pulling from library/hello-world +e6590344b1a5: Pull complete +Digest: sha256:7e1a4e2d11e2ac7a8c3f768d4166c2defeb09d2a750b010412b6ea13de1efb19 +Status: Downloaded newer image for hello-world:latest -Test Spark works by running: +Hello from Docker! +This message shows that your installation appears to be working correctly. -```bash -spark-shell -``` +To generate this message, Docker took the following steps: + 1. The Docker client contacted the Docker daemon. + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. + (amd64) + 3. The Docker daemon created a new container from that image which runs the + executable that produces the output you are currently reading. + 4. The Docker daemon streamed that output to the Docker client, which sent it + to your terminal. -You should see an output similar to: +To try something more ambitious, you can run an Ubuntu container with: + $ docker run -it ubuntu bash -```bash -Setting default log level to "WARN". -To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). -25/01/15 11:33:07 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable -Spark context Web UI available at http://de-vm-lrae-test.europe-north1-b.c.wagon-de.internal:4040 -Spark context available as 'sc' (master = local[*], app id = local-1736940788403). -Spark session available as 'spark'. -Welcome to - ____ __ - / __/__ ___ _____/ /__ - _\ \/ _ \/ _ `/ __/ '_/ - /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 - /_/ - -Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_432) -Type in expressions to have them evaluated. -Type :help for more information. - -scala> -``` -Type `:quit` and hit enter to exit the spark-shell and continue. - - -## Python & Pip - -Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. We are going to use Python 3.12 ([3.12.8](https://www.python.org/downloads/release/python-3128/)). - -Let's install pyenv to manage our python versions: - -```bash -git clone https://github.com/pyenv/pyenv.git ~/.pyenv -source ~/.zprofile -exec zsh -``` - -We'll also install a useful `pyenv` plugin called [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv). Although we will be using `poetry` for Python package and virtual environment management, `pyenv-virtualenv` is useful for controlling python versions locally. - -```bash -git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv -exec zsh -``` +Share images, automate workflows, and more with a free Docker ID: + https://hub.docker.com/ -Now install Python 3.12.8: -```bash -pyenv install 3.12.8 -pyenv global 3.12.8 +For more examples and ideas, visit: + https://docs.docker.com/get-started/ ``` -Now `python --version` should return `3.12.8` - - -## Pipx - -Next we are going to install [pipx](https://pypa.github.io/pipx/) to install python packages we want globally available while still using virtual environments. -Let's upgrade `pip` first: +#### Kubernetes -```bash -pip install --upgrade pip -``` - -And install `pipx`: +We can start by testing `minikube`: ```bash -python -m pip install --user pipx # --user so that each ubuntu user can have his own 'pipx' -python -m pipx ensurepath -exec zsh +# Start +minikube start ``` -Lets install a [tldr](https://github.com/tldr-pages/tldr) with pipx +Should return: ```bash -pipx install tldr +๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) +โœจ Automatically selected the docker driver. Other choices: none, ssh +๐Ÿ“Œ Using Docker driver with root privileges +๐Ÿ‘ Starting "minikube" primary control-plane node in "minikube" cluster +๐Ÿšœ Pulling base image v0.0.46 ... +๐Ÿ’พ Downloading Kubernetes v1.32.0 preload ... + > gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 88.19 M + > preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 32.20 M +๐Ÿ”ฅ Creating docker container (CPUs=2, Memory=3900MB) ... +๐Ÿณ Preparing Kubernetes v1.32.0 on Docker 27.4.1 ... + โ–ช Generating certificates and keys ... + โ–ช Booting up control plane ... + โ–ช Configuring RBAC rules ... +๐Ÿ”— Configuring bridge CNI (Container Networking Interface) ... +๐Ÿ”Ž Verifying Kubernetes components... + โ–ช Using image gcr.io/k8s-minikube/storage-provisioner:v5 +๐ŸŒŸ Enabled addons: storage-provisioner, default-storageclass +๐Ÿ„ Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default ``` -Now `tldr` should be globally available (for the current user), test it out with: +And then make sure the kubernetes CLI utility, `kubectl`, works with: ```bash -tldr ls +# Get pods +kubectl get po -A ``` -Much more readable than the classic `man ls` (although sometimes you will still need to delve into the man pages to get all of the details!) and it even has pages not included in man such as `tldr gh`: - -tldr - - -Lets add a few more packages we want globally available - -### black - -[black](https://black.readthedocs.io/en/stable/) for helping to format code +Should return something similar too: ```bash -pipx install black +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s +kube-system etcd-minikube 1/1 Running 0 78s +kube-system kube-apiserver-minikube 1/1 Running 0 76s +kube-system kube-controller-manager-minikube 1/1 Running 0 76s +kube-system kube-proxy-stk77 1/1 Running 0 72s +kube-system kube-scheduler-minikube 1/1 Running 0 76s +kube-system storage-provisioner 1/1 Running 1 (41s ago) 75s ``` -### Poetry - -[Poetry](https://python-poetry.org/) is a modern Python package manager we will use throughout the bootcamp. - -Install Poetry running the following command in your VS Code terminal: +And because `minikube` is resource intensive, stop it for now with: ```bash -pipx install poetry +# Stop +minikube delete --all ``` -Then, let's update default poetry behavior so that virtual envs are always created where `poetry install` is run. -During the bootcamp, you'll see a `.venv` folder being created inside each challenge folder. +Should return: ```bash -poetry config virtualenvs.in-project true -``` - -Finally, update your VScode settings to tell it that this `.venv` relative folder path will be your default interpreter! - -1. Open the Command Palette ( ๐ŸชŸ ctrl + shift + P / ๐ŸŽ cmd + shift + P ) -2. Search for: **Preference: Open Remote Settings (JSON)** - when you open your settings that should be two panels. -3. In the panel that opens on the **right side** search for the line: `python.defaultInterpreterPath` -4. Replace the value (probably `"~/.pyenv/shims/python"`) so that it looks like: - -```yml -"python.defaultInterpreterPath": ".venv/bin/python", +๐Ÿ”ฅ Deleting "minikube" in docker ... +๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... +๐Ÿ’€ Removed all traces of the "minikube" cluster. +๐Ÿ”ฅ Successfully deleted all profiles ``` -## Direnv - -[Direnv](https://direnv.net/) is a great utility that will look for `.envrc` files in your directories. When you `cd` into directories with a `.envrc` files, paths will automatically be updated. In our case, this will simplify our workflow and allow us to not have to worry about Poetry managed Python virtual environments. +#### Terraform -1. First, setup the *direnv hook* to your zsh shell so that direnv gets activated anytime a `.envrc` file exists in current working directory. - -```bash -code ~/.zshrc -``` +To test: ```bash -plugins=(git gitfast ... pyenv ssh-agent direnv) # add `direnv` to the existing list of plugins +terraform --version ``` -2. Second, let's configure what will happens anytime `.envrc` file is found +Should return: ```bash -code ~/.direnvrc +Terraform v1.11.2 +on linux_amd64 ``` -- Paste the following lines - ```bash - layout_poetry() { - if [[ ! -f pyproject.toml ]]; then - log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.' - exit 2 - fi - # create venv if it doesn't exist - poetry run true - - export VIRTUAL_ENV=$(poetry env info --path) - export POETRY_ACTIVE=1 - PATH_add "$VIRTUAL_ENV/bin" - } - ``` -- Save and close the file - -๐Ÿ˜Ž Now, **anytime you `cd` into a challenge folder which contains a `.envrc` file which contains `layout_poetry()` command inside, the function will get executed and your virtual env will switch to the poetry one that is defined by the `pyproject.toml` !** -- No need to prefix all commands with `poetry run `, but simply `` -- Each challenge will have its own virtual env, and it will be seamless for you to switch between challenges/envs - -## Let's Make! +#### Spark -Lets clone the challenges onto your **virtual machine** +To test: ```bash -export GITHUB_USERNAME=`gh api user | jq -r '.login'` -echo $GITHUB_USERNAME -``` - -Then: - -```bash -mkdir -p ~/code/$GITHUB_USERNAME && cd $_ -gh repo fork lewagon/data-engineering-challenges --clone +spark-shell ``` -Our setup will look a bit like this: - - - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - -Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! +Should take you into the spark shell that looks like: ```bash -cd data-engineering-challenges -git remote -v -# origin git@github.com:your_github_username/data-engineering-challenges.git (fetch) -# origin git@github.com:your_github_username/data-engineering-challenges.git (push) -# upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -# upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - -From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: - -- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) -- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) -- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder +Setting default log level to "WARN". +To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). +25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable +Spark context Web UI available at http://lw-de-vm.europe-north1-b.c.wagon-de.internal:4040 +Spark context available as 'sc' (master = local[*], app id = local-1742288096829). +Spark session available as 'spark'. +Welcome to + ____ __ + / __/__ ___ _____/ /__ + _\ \/ _ \/ _ `/ __/ '_/ + /___/ .__/\_,_/_/ /_/\_\ version 3.5.3 + /_/ -Let's make! +Using Scala version 2.12.18 (OpenJDK 64-Bit Server VM, Java 1.8.0_442) +Type in expressions to have them evaluated. +Type :help for more information. -```bash -make install +scala> ``` -This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. +Type `:quit` and hit enter to exit the spark-shell and continue. -โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ +That's everything for now! From a8ee0a7b087dbd455f2d189def313e4eb79e29f7 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 17:33:30 +0200 Subject: [PATCH 24/44] updated partials for typos, readability, and order --- _partials/gcp_adc_auth.md | 2 ++ _partials/gcp_cli_oauth.md | 6 ++--- _partials/repo_overview.md | 31 +++++++++-------------- _partials/terraform.md | 8 +++--- _partials/terraform_vm.md | 30 +++++++++++++++++----- _partials/ubuntu_ansible_part1.md | 12 +++++---- _partials/ubuntu_ansible_part2.md | 14 +++++------ _partials/ubuntu_vm_test.md | 40 ++++++++---------------------- _partials/vscode_ssh_connection.md | 6 ++--- 9 files changed, 73 insertions(+), 76 deletions(-) diff --git a/_partials/gcp_adc_auth.md b/_partials/gcp_adc_auth.md index ca632aa..fb02ccc 100644 --- a/_partials/gcp_adc_auth.md +++ b/_partials/gcp_adc_auth.md @@ -11,3 +11,5 @@ To authenticate your Application Default Credentials, in your terminal run: ```bash gcloud auth application-default login ``` + +And follow the prompts. diff --git a/_partials/gcp_cli_oauth.md b/_partials/gcp_cli_oauth.md index 5cb0b2d..e4a5240 100644 --- a/_partials/gcp_cli_oauth.md +++ b/_partials/gcp_cli_oauth.md @@ -1,6 +1,6 @@ ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -18,7 +18,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -26,7 +26,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True diff --git a/_partials/repo_overview.md b/_partials/repo_overview.md index 01c1869..6160191 100644 --- a/_partials/repo_overview.md +++ b/_partials/repo_overview.md @@ -1,34 +1,27 @@ ## Let's Make! -Lets clone the challenges onto your **virtual machine** - -```bash -export GITHUB_USERNAME=`gh api user | jq -r '.login'` -echo $GITHUB_USERNAME -``` - -Then: - -```bash -mkdir -p ~/code/$GITHUB_USERNAME && cd $_ -gh repo fork lewagon/data-engineering-challenges --clone -``` +Almost there! In the second ansible playbook, the `lewagon/data-engineering-challenges` repository was forked from Le Wagon to you. Let's review how it works. Our setup will look a bit like this: - +![](/images/repo_overview.png) This allows you to work on challenges, but if we push any changes to the content, you can still access them! Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! ```bash -cd data-engineering-challenges +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges git remote -v -# origin git@github.com:your_github_username/data-engineering-challenges.git (fetch) -# origin git@github.com:your_github_username/data-engineering-challenges.git (push) -# upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -# upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` + +Should return: + +``` +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) ``` From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: diff --git a/_partials/terraform.md b/_partials/terraform.md index 887fce2..364ffda 100644 --- a/_partials/terraform.md +++ b/_partials/terraform.md @@ -1,6 +1,6 @@ ## Terraform -Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. $MAC_START You can use `brew` to install terraform. In your terminal, run: @@ -16,12 +16,12 @@ To install terraform, download the binary from the Terraform install page at thi TODO: Unsure if anything needs to be added to PATH to get it to work $WINDOWS_END $LINUX_START -Install some basic requirements +Install some basic requirements: ```bash sudo apt-get update && sudo apt-get install -y gnupg software-properties-common ``` -Terraform is not available to apt by default so we need to make it available! +Terraform is not available to **apt** by default so we need to make it available. ```bash wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ @@ -40,7 +40,7 @@ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ sudo tee /etc/apt/sources.list.d/hashicorp.list ``` -Now we can install terraform directly with apt ๐Ÿ‘‡ +Now we can install terraform directly with **apt** ๐Ÿ‘‡ ```bash sudo apt update sudo apt-get install terraform diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index 079e1f2..daa3c03 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -15,13 +15,11 @@ Creating and running a Virtual Machine on Google Cloud Platform costs money. If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! - -You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! ### Download terraform files -We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. +We almost have all the necessary parts to create your VM using **terraform**. We need to download the terraform files and change a few values. First we'll create a folder and download the terraform files with: @@ -76,8 +74,8 @@ instance_user = "" We'll need to change some values in this file. Here's were you can find the required values: - **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. -- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. -- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. - **instance_user:** in your terminal, run `whoami` and hit enter. After completing this file, it should look similar to: @@ -92,6 +90,25 @@ instance_user = "taylorswift" # result of `whoami` Make sure to save the `terraform.tfvars` file and then run: +$MAC_START +```bash +cd ~/wagon-de-bootcamp + +terraform init + +terraform plan +``` +$MAC_END +$WINDOWS_START +```cmd +cd %USERPROFILE%\wagon-de-bootcamp + +terraform init + +terraform plan +``` +$WINDOWS_END +$LINUX_START ```bash cd ~/wagon-de-bootcamp @@ -99,6 +116,7 @@ terraform init terraform plan ``` +$LINUX_END And check the output, if you have any errors, raise a ticket with a teacher. diff --git a/_partials/ubuntu_ansible_part1.md b/_partials/ubuntu_ansible_part1.md index 27baa11..ff41a31 100644 --- a/_partials/ubuntu_ansible_part1.md +++ b/_partials/ubuntu_ansible_part1.md @@ -1,6 +1,6 @@ ## VM configuration with Ansible -We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. +We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. Let's start by confirming that ansible is installed. In your terminal run: @@ -22,11 +22,11 @@ ansible [core 2.17.9] libyaml = True ``` -If not, raise a ticket with a teacher. +โ— If not, raise a ticket with a teacher. ### Ansible Playbook 1 -If everything looks ok, lets create a folder and download the ansible files: +Create a folder and download the ansible files: ```bash mkdir -p ~/vm-ansible-setup/playbooks @@ -45,7 +45,7 @@ ansible-playbook playbooks/setup_vm_part1.yml And the playbook should start running! -โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +โ— If an errors occur, raise a ticket with a teacher. You can safely run the playbook again. ### What is the playbook installing? @@ -62,6 +62,8 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: +Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) + +Your terminal should be `zsh`. diff --git a/_partials/ubuntu_ansible_part2.md b/_partials/ubuntu_ansible_part2.md index 2541398..60cb892 100644 --- a/_partials/ubuntu_ansible_part2.md +++ b/_partials/ubuntu_ansible_part2.md @@ -2,7 +2,7 @@ ### Ansible Playbook 2 -We'll be using a second **ansible** playbook to further configure your Virtual Machine. +We'll be using a second **Ansible** playbook to further configure your Virtual Machine. Start by downloading the ansible playbook: @@ -21,6 +21,12 @@ And the playbook should start running! โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +
+โ“ Why two Ansible playbooks? + +This second ansible playbook requires GitHub authorisation to fork the `lewagon/data-engineering-challenges` repository and it is also editing some of the Le Wagon recommended **dotfiles**. So we separated the process into two steps. +
+ ### What is the playbook installing? This playbook is installing and configuring a things, while the playbook is running, let's go through them: @@ -64,12 +70,6 @@ Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. W The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -Here is an image of how the Repository setup works: - -![](/images/repo_overview.png) - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - ### Restart Virtual Machine Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). diff --git a/_partials/ubuntu_vm_test.md b/_partials/ubuntu_vm_test.md index 716dd49..c007473 100644 --- a/_partials/ubuntu_vm_test.md +++ b/_partials/ubuntu_vm_test.md @@ -1,6 +1,6 @@ ## Check your Virtual Machine Setup -We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks in the terminal to make sure that everything has installed correctly. โ— If any of these checks error out, raise a ticket with a teacher. @@ -14,7 +14,7 @@ python --version Should return: -```bash +``` Python 3.12.8 ``` @@ -28,7 +28,7 @@ pyenv versions Should return: -```bash +``` system * 3.12.8 (set by /home//.pyenv/version) ``` @@ -45,7 +45,7 @@ pipx list Should return something similar too: -```bash +``` venvs are in /home//.local/share/pipx/venvs apps are exposed on your $PATH at /home//.local/bin manual pages are exposed at /home//.local/share/man @@ -58,24 +58,6 @@ manual pages are exposed at /home//.local/share/man - man1/tldr.1 ``` -#### Data Engineering Challenges repo remotes - -To test: - -```bash -cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges -git remote -v -``` - -Should return: - -```bash -origin git@github.com:/data-engineering-challenges.git (fetch) -origin git@github.com:/data-engineering-challenges.git (push) -upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - #### Docker To test: @@ -86,7 +68,7 @@ docker run hello-world Should return: -```bash +``` Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world e6590344b1a5: Pull complete @@ -126,7 +108,7 @@ minikube start Should return: -```bash +``` ๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) โœจ Automatically selected the docker driver. Other choices: none, ssh ๐Ÿ“Œ Using Docker driver with root privileges @@ -156,7 +138,7 @@ kubectl get po -A Should return something similar too: -```bash +``` NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s kube-system etcd-minikube 1/1 Running 0 78s @@ -176,7 +158,7 @@ minikube delete --all Should return: -```bash +``` ๐Ÿ”ฅ Deleting "minikube" in docker ... ๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... ๐Ÿ’€ Removed all traces of the "minikube" cluster. @@ -193,7 +175,7 @@ terraform --version Should return: -```bash +``` Terraform v1.11.2 on linux_amd64 ``` @@ -208,7 +190,7 @@ spark-shell Should take you into the spark shell that looks like: -```bash +``` Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). 25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable @@ -231,4 +213,4 @@ scala> Type `:quit` and hit enter to exit the spark-shell and continue. -That's everything for now! +That's all the testing we'll do for now! diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md index f6751de..988702e 100644 --- a/_partials/vscode_ssh_connection.md +++ b/_partials/vscode_ssh_connection.md @@ -18,11 +18,11 @@ For example, try running: # $ ssh lw-de-vm-.. ``` -To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: +To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) -It should bring up a menu: +It should bring up a menu, click on **Connect to Host...**: ![](/images/vscode_remote_menu.png) @@ -30,7 +30,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) From 57b33203bf3cc012f1d1280fa37f418ddb55fe10 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 15:34:28 +0000 Subject: [PATCH 25/44] setup guides generated --- LINUX.md | 104 +++++++++++++++++++++++------------------------------ WINDOWS.md | 102 ++++++++++++++++++++++------------------------------ macOS.md | 98 +++++++++++++++++++++----------------------------- 3 files changed, 128 insertions(+), 176 deletions(-) diff --git a/LINUX.md b/LINUX.md index d60679c..dbf4848 100644 --- a/LINUX.md +++ b/LINUX.md @@ -367,7 +367,7 @@ gcloud --version ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -385,7 +385,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -393,7 +393,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -405,14 +405,14 @@ Your active configuration is: [default] ## Terraform -Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. -Install some basic requirements +Install some basic requirements: ```bash sudo apt-get update && sudo apt-get install -y gnupg software-properties-common ``` -Terraform is not available to apt by default so we need to make it available! +Terraform is not available to **apt** by default so we need to make it available. ```bash wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ @@ -431,7 +431,7 @@ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ sudo tee /etc/apt/sources.list.d/hashicorp.list ``` -Now we can install terraform directly with apt ๐Ÿ‘‡ +Now we can install terraform directly with **apt** ๐Ÿ‘‡ ```bash sudo apt update sudo apt-get install terraform @@ -461,13 +461,11 @@ Creating and running a Virtual Machine on Google Cloud Platform costs money. If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! - -You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! ### Download terraform files -We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. +We almost have all the necessary parts to create your VM using **terraform**. We need to download the terraform files and change a few values. First we'll create a folder and download the terraform files with: @@ -496,8 +494,8 @@ instance_user = "" We'll need to change some values in this file. Here's were you can find the required values: - **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. -- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. -- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. - **instance_user:** in your terminal, run `whoami` and hit enter. After completing this file, it should look similar to: @@ -551,11 +549,11 @@ For example, try running: # $ ssh lw-de-vm-.. ``` -To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: +To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) -It should bring up a menu: +It should bring up a menu, click on **Connect to Host...**: ![](/images/vscode_remote_menu.png) @@ -563,7 +561,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -590,10 +588,12 @@ To authenticate your Application Default Credentials, in your terminal run: gcloud auth application-default login ``` +And follow the prompts. + ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -611,7 +611,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -619,7 +619,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -631,7 +631,7 @@ Your active configuration is: [default] ## VM configuration with Ansible -We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. +We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. Let's start by confirming that ansible is installed. In your terminal run: @@ -653,11 +653,11 @@ ansible [core 2.17.9] libyaml = True ``` -If not, raise a ticket with a teacher. +โ— If not, raise a ticket with a teacher. ### Ansible Playbook 1 -If everything looks ok, lets create a folder and download the ansible files: +Create a folder and download the ansible files: ```bash mkdir -p ~/vm-ansible-setup/playbooks @@ -676,7 +676,7 @@ ansible-playbook playbooks/setup_vm_part1.yml And the playbook should start running! -โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +โ— If an errors occur, raise a ticket with a teacher. You can safely run the playbook again. ### What is the playbook installing? @@ -693,10 +693,12 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: +Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) +Your terminal should be `zsh`. + ## GitHub CLI @@ -900,7 +902,7 @@ you don't want your email to appear in public repositories you may contribute to ### Ansible Playbook 2 -We'll be using a second **ansible** playbook to further configure your Virtual Machine. +We'll be using a second **Ansible** playbook to further configure your Virtual Machine. Start by downloading the ansible playbook: @@ -919,6 +921,12 @@ And the playbook should start running! โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +
+โ“ Why two Ansible playbooks? + +This second ansible playbook requires GitHub authorisation to fork the `lewagon/data-engineering-challenges` repository and it is also editing some of the Le Wagon recommended **dotfiles**. So we separated the process into two steps. +
+ ### What is the playbook installing? This playbook is installing and configuring a things, while the playbook is running, let's go through them: @@ -962,12 +970,6 @@ Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. W The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -Here is an image of how the Repository setup works: - -![](/images/repo_overview.png) - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - ### Restart Virtual Machine Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). @@ -985,7 +987,7 @@ When the VM is completely off, turn it on again by selecting the check box next ## Check your Virtual Machine Setup -We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks in the terminal to make sure that everything has installed correctly. โ— If any of these checks error out, raise a ticket with a teacher. @@ -999,7 +1001,7 @@ python --version Should return: -```bash +``` Python 3.12.8 ``` @@ -1013,7 +1015,7 @@ pyenv versions Should return: -```bash +``` system * 3.12.8 (set by /home//.pyenv/version) ``` @@ -1030,7 +1032,7 @@ pipx list Should return something similar too: -```bash +``` venvs are in /home//.local/share/pipx/venvs apps are exposed on your $PATH at /home//.local/bin manual pages are exposed at /home//.local/share/man @@ -1043,24 +1045,6 @@ manual pages are exposed at /home//.local/share/man - man1/tldr.1 ``` -#### Data Engineering Challenges repo remotes - -To test: - -```bash -cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges -git remote -v -``` - -Should return: - -```bash -origin git@github.com:/data-engineering-challenges.git (fetch) -origin git@github.com:/data-engineering-challenges.git (push) -upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - #### Docker To test: @@ -1071,7 +1055,7 @@ docker run hello-world Should return: -```bash +``` Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world e6590344b1a5: Pull complete @@ -1111,7 +1095,7 @@ minikube start Should return: -```bash +``` ๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) โœจ Automatically selected the docker driver. Other choices: none, ssh ๐Ÿ“Œ Using Docker driver with root privileges @@ -1141,7 +1125,7 @@ kubectl get po -A Should return something similar too: -```bash +``` NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s kube-system etcd-minikube 1/1 Running 0 78s @@ -1161,7 +1145,7 @@ minikube delete --all Should return: -```bash +``` ๐Ÿ”ฅ Deleting "minikube" in docker ... ๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... ๐Ÿ’€ Removed all traces of the "minikube" cluster. @@ -1178,7 +1162,7 @@ terraform --version Should return: -```bash +``` Terraform v1.11.2 on linux_amd64 ``` @@ -1193,7 +1177,7 @@ spark-shell Should take you into the spark shell that looks like: -```bash +``` Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). 25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable @@ -1216,7 +1200,7 @@ scala> Type `:quit` and hit enter to exit the spark-shell and continue. -That's everything for now! +That's all the testing we'll do for now! diff --git a/WINDOWS.md b/WINDOWS.md index 69585a2..bea4c0c 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -328,7 +328,7 @@ gcloud --version ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -346,7 +346,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -354,7 +354,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -366,7 +366,7 @@ Your active configuration is: [default] ## Terraform -Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. To install terraform, download the binary from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). @@ -396,13 +396,11 @@ Creating and running a Virtual Machine on Google Cloud Platform costs money. If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! - -You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! ### Download terraform files -We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. +We almost have all the necessary parts to create your VM using **terraform**. We need to download the terraform files and change a few values. First we'll create a folder and download the terraform files with: @@ -435,8 +433,8 @@ instance_user = "" We'll need to change some values in this file. Here's were you can find the required values: - **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. -- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. -- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. - **instance_user:** in your terminal, run `whoami` and hit enter. After completing this file, it should look similar to: @@ -451,8 +449,8 @@ instance_user = "taylorswift" # result of `whoami` Make sure to save the `terraform.tfvars` file and then run: -```bash -cd ~/wagon-de-bootcamp +```cmd +cd %USERPROFILE%\wagon-de-bootcamp terraform init @@ -490,11 +488,11 @@ For example, try running: # $ ssh lw-de-vm-.. ``` -To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: +To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) -It should bring up a menu: +It should bring up a menu, click on **Connect to Host...**: ![](/images/vscode_remote_menu.png) @@ -502,7 +500,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -529,10 +527,12 @@ To authenticate your Application Default Credentials, in your terminal run: gcloud auth application-default login ``` +And follow the prompts. + ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -550,7 +550,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -558,7 +558,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -570,7 +570,7 @@ Your active configuration is: [default] ## VM configuration with Ansible -We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. +We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. Let's start by confirming that ansible is installed. In your terminal run: @@ -592,11 +592,11 @@ ansible [core 2.17.9] libyaml = True ``` -If not, raise a ticket with a teacher. +โ— If not, raise a ticket with a teacher. ### Ansible Playbook 1 -If everything looks ok, lets create a folder and download the ansible files: +Create a folder and download the ansible files: ```bash mkdir -p ~/vm-ansible-setup/playbooks @@ -615,7 +615,7 @@ ansible-playbook playbooks/setup_vm_part1.yml And the playbook should start running! -โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +โ— If an errors occur, raise a ticket with a teacher. You can safely run the playbook again. ### What is the playbook installing? @@ -632,10 +632,12 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: +Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) +Your terminal should be `zsh`. + ## GitHub CLI @@ -839,7 +841,7 @@ you don't want your email to appear in public repositories you may contribute to ### Ansible Playbook 2 -We'll be using a second **ansible** playbook to further configure your Virtual Machine. +We'll be using a second **Ansible** playbook to further configure your Virtual Machine. Start by downloading the ansible playbook: @@ -858,6 +860,12 @@ And the playbook should start running! โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +
+โ“ Why two Ansible playbooks? + +This second ansible playbook requires GitHub authorisation to fork the `lewagon/data-engineering-challenges` repository and it is also editing some of the Le Wagon recommended **dotfiles**. So we separated the process into two steps. +
+ ### What is the playbook installing? This playbook is installing and configuring a things, while the playbook is running, let's go through them: @@ -901,12 +909,6 @@ Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. W The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -Here is an image of how the Repository setup works: - -![](/images/repo_overview.png) - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - ### Restart Virtual Machine Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). @@ -924,7 +926,7 @@ When the VM is completely off, turn it on again by selecting the check box next ## Check your Virtual Machine Setup -We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks in the terminal to make sure that everything has installed correctly. โ— If any of these checks error out, raise a ticket with a teacher. @@ -938,7 +940,7 @@ python --version Should return: -```bash +``` Python 3.12.8 ``` @@ -952,7 +954,7 @@ pyenv versions Should return: -```bash +``` system * 3.12.8 (set by /home//.pyenv/version) ``` @@ -969,7 +971,7 @@ pipx list Should return something similar too: -```bash +``` venvs are in /home//.local/share/pipx/venvs apps are exposed on your $PATH at /home//.local/bin manual pages are exposed at /home//.local/share/man @@ -982,24 +984,6 @@ manual pages are exposed at /home//.local/share/man - man1/tldr.1 ``` -#### Data Engineering Challenges repo remotes - -To test: - -```bash -cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges -git remote -v -``` - -Should return: - -```bash -origin git@github.com:/data-engineering-challenges.git (fetch) -origin git@github.com:/data-engineering-challenges.git (push) -upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - #### Docker To test: @@ -1010,7 +994,7 @@ docker run hello-world Should return: -```bash +``` Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world e6590344b1a5: Pull complete @@ -1050,7 +1034,7 @@ minikube start Should return: -```bash +``` ๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) โœจ Automatically selected the docker driver. Other choices: none, ssh ๐Ÿ“Œ Using Docker driver with root privileges @@ -1080,7 +1064,7 @@ kubectl get po -A Should return something similar too: -```bash +``` NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s kube-system etcd-minikube 1/1 Running 0 78s @@ -1100,7 +1084,7 @@ minikube delete --all Should return: -```bash +``` ๐Ÿ”ฅ Deleting "minikube" in docker ... ๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... ๐Ÿ’€ Removed all traces of the "minikube" cluster. @@ -1117,7 +1101,7 @@ terraform --version Should return: -```bash +``` Terraform v1.11.2 on linux_amd64 ``` @@ -1132,7 +1116,7 @@ spark-shell Should take you into the spark shell that looks like: -```bash +``` Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). 25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable @@ -1155,7 +1139,7 @@ scala> Type `:quit` and hit enter to exit the spark-shell and continue. -That's everything for now! +That's all the testing we'll do for now! diff --git a/macOS.md b/macOS.md index 8ef427d..4ef52a1 100644 --- a/macOS.md +++ b/macOS.md @@ -405,7 +405,7 @@ gcloud --version ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -423,7 +423,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -431,7 +431,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -443,7 +443,7 @@ Your active configuration is: [default] ## Terraform -Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud! +Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. You can use `brew` to install terraform. In your terminal, run: @@ -476,13 +476,11 @@ Creating and running a Virtual Machine on Google Cloud Platform costs money. If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month! But you can drastically reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! - -You will always pay for the Storage (Hard Disk Drive) and Static IP. Google can't rent out stateful resources to other users without wiping your data. +The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! ### Download terraform files -We almost have all the necessary parts to create your VM using **terraform**. We just need to download the terraform files and change a few values. +We almost have all the necessary parts to create your VM using **terraform**. We need to download the terraform files and change a few values. First we'll create a folder and download the terraform files with: @@ -511,8 +509,8 @@ instance_user = "" We'll need to change some values in this file. Here's were you can find the required values: - **project_id:** from the GCP Console at this [link here](https://console.cloud.google.com). - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. -- **zone:** Zone is a subset of region. it is usually the same as region appended with a `-a`, `-b`, or `-c`. -- **instance_name:** we recommend naming this: `lw-de-vm-`. Replacing `` +- **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. +- **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. - **instance_user:** in your terminal, run `whoami` and hit enter. After completing this file, it should look similar to: @@ -566,11 +564,11 @@ For example, try running: # $ ssh lw-de-vm-.. ``` -To connect to your Virtual Machine, click on the small symbol at the very far bottom-left of your VS Code: +To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) -It should bring up a menu: +It should bring up a menu, click on **Connect to Host...**: ![](/images/vscode_remote_menu.png) @@ -578,7 +576,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. This is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -605,10 +603,12 @@ To authenticate your Application Default Credentials, in your terminal run: gcloud auth application-default login ``` +And follow the prompts. + ### Authenticate gcloud -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with google services. +We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. To authenticate `gcloud`, run: @@ -626,7 +626,7 @@ To set your project, replace `` with your GCP Project ID and ru gcloud config set project ``` -To confirm your setup, run: +Confirm your setup with: ```bash gcloud config list @@ -634,7 +634,7 @@ gcloud config list You should get an output similar to: -```bash +``` [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -646,7 +646,7 @@ Your active configuration is: [default] ## VM configuration with Ansible -We'll be using **ansible** to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. +We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. Let's start by confirming that ansible is installed. In your terminal run: @@ -668,11 +668,11 @@ ansible [core 2.17.9] libyaml = True ``` -If not, raise a ticket with a teacher. +โ— If not, raise a ticket with a teacher. ### Ansible Playbook 1 -If everything looks ok, lets create a folder and download the ansible files: +Create a folder and download the ansible files: ```bash mkdir -p ~/vm-ansible-setup/playbooks @@ -691,7 +691,7 @@ ansible-playbook playbooks/setup_vm_part1.yml And the playbook should start running! -โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +โ— If an errors occur, raise a ticket with a teacher. You can safely run the playbook again. ### What is the playbook installing? @@ -708,10 +708,12 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can) and re-open it (you might have to do it a few times) until it looks similar to: +Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) +Your terminal should be `zsh`. + ## GitHub CLI @@ -915,7 +917,7 @@ you don't want your email to appear in public repositories you may contribute to ### Ansible Playbook 2 -We'll be using a second **ansible** playbook to further configure your Virtual Machine. +We'll be using a second **Ansible** playbook to further configure your Virtual Machine. Start by downloading the ansible playbook: @@ -934,6 +936,12 @@ And the playbook should start running! โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. +
+โ“ Why two Ansible playbooks? + +This second ansible playbook requires GitHub authorisation to fork the `lewagon/data-engineering-challenges` repository and it is also editing some of the Le Wagon recommended **dotfiles**. So we separated the process into two steps. +
+ ### What is the playbook installing? This playbook is installing and configuring a things, while the playbook is running, let's go through them: @@ -977,12 +985,6 @@ Ubuntu 22.04 has Python pre-installed, but not the version we're going to use. W The challenges that you'll be working on throughout the bootcamp! The playbook is forking the **data-engineering-challenges** repository from **lewagon** to your own GitHub user. Then cloning that repository from your GitHub account down onto your Virtual Machine. -Here is an image of how the Repository setup works: - -![](/images/repo_overview.png) - -This allows you to work on challenges, but if we push any changes to the content, you can still access them! - ### Restart Virtual Machine Once the playbook has finished running, you need to completely shutdown your Virtual Machine so that some of the configuration updates (specifically **pyenv** and **Docker**). @@ -1000,7 +1002,7 @@ When the VM is completely off, turn it on again by selecting the check box next ## Check your Virtual Machine Setup -We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks to make sure that everything has installed correctly. +We've used two ansible playbooks to configure our Virtual Machine. Let's run some manual checks in the terminal to make sure that everything has installed correctly. โ— If any of these checks error out, raise a ticket with a teacher. @@ -1014,7 +1016,7 @@ python --version Should return: -```bash +``` Python 3.12.8 ``` @@ -1028,7 +1030,7 @@ pyenv versions Should return: -```bash +``` system * 3.12.8 (set by /home//.pyenv/version) ``` @@ -1045,7 +1047,7 @@ pipx list Should return something similar too: -```bash +``` venvs are in /home//.local/share/pipx/venvs apps are exposed on your $PATH at /home//.local/bin manual pages are exposed at /home//.local/share/man @@ -1058,24 +1060,6 @@ manual pages are exposed at /home//.local/share/man - man1/tldr.1 ``` -#### Data Engineering Challenges repo remotes - -To test: - -```bash -cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges -git remote -v -``` - -Should return: - -```bash -origin git@github.com:/data-engineering-challenges.git (fetch) -origin git@github.com:/data-engineering-challenges.git (push) -upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) -upstream git@github.com:lewagon/data-engineering-challenges.git (push) -``` - #### Docker To test: @@ -1086,7 +1070,7 @@ docker run hello-world Should return: -```bash +``` Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world e6590344b1a5: Pull complete @@ -1126,7 +1110,7 @@ minikube start Should return: -```bash +``` ๐Ÿ˜„ minikube v1.35.0 on Ubuntu 22.04 (amd64) โœจ Automatically selected the docker driver. Other choices: none, ssh ๐Ÿ“Œ Using Docker driver with root privileges @@ -1156,7 +1140,7 @@ kubectl get po -A Should return something similar too: -```bash +``` NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-668d6bf9bc-mg7b6 1/1 Running 0 72s kube-system etcd-minikube 1/1 Running 0 78s @@ -1176,7 +1160,7 @@ minikube delete --all Should return: -```bash +``` ๐Ÿ”ฅ Deleting "minikube" in docker ... ๐Ÿ”ฅ Removing /home//.minikube/machines/minikube ... ๐Ÿ’€ Removed all traces of the "minikube" cluster. @@ -1193,7 +1177,7 @@ terraform --version Should return: -```bash +``` Terraform v1.11.2 on linux_amd64 ``` @@ -1208,7 +1192,7 @@ spark-shell Should take you into the spark shell that looks like: -```bash +``` Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). 25/03/18 08:54:55 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable @@ -1231,7 +1215,7 @@ scala> Type `:quit` and hit enter to exit the spark-shell and continue. -That's everything for now! +That's all the testing we'll do for now! From e724badfa0b34e5bc8c690f785f37cfde43ba17b Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Tue, 18 Mar 2025 18:10:29 +0200 Subject: [PATCH 26/44] partials: typos and syntax --- _partials/intro.md | 20 ++++++++++---------- _partials/terraform_vm.md | 2 +- _partials/ubuntu_ansible_part1.md | 4 ++-- _partials/vscode_ssh_connection.md | 12 ++++++++++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/_partials/intro.md b/_partials/intro.md index 560b29a..0b12a82 100644 --- a/_partials/intro.md +++ b/_partials/intro.md @@ -6,9 +6,9 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: -This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. -- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! -- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! +This setup is largely automated with **Terraform** and **Ansible**. There are three main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses, databases and more! +- **Ansible** is used to configure linux machines with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! ## Part 1: Setup your local computer @@ -16,8 +16,8 @@ In this section you'll setup your local computer and create some accounts. It wi 1. Install some communication tools: Zoom, Slack 2. Create some accounts: Github, Google Cloud Platform (GCP) 3. Install Visual Studio Code (VS Code) -4. Install and authentication the GCP command line tool: `gcloud`. -5. Install **terraform** on your local computer. +4. Install and authentication the GCP command line tool: `gcloud` +5. Install **terraform** on your local computer 6. Create your virtual machine with **terraform** and connect to it with **VS Code**! ## Part 2: Configure your Virtual Machine Part 1 @@ -26,18 +26,18 @@ All parts of this section happen on your virtual machine. This section includes: 1. Authenticate your virtual machine with `gcloud` -2. Download and run an **ansible** playbook to partially configure your virtual machine. +2. Download and run an **ansible** playbook to partially configure your virtual machine 3. Login to the Github command line tool on your virtual machine -4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! +4. Copy the Le Wagon recommended **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! ## Part 3: Configure your Virtual Machine Part 2 All parts of this section happen on your virtual machine. In this section you will: -1. Download and run a second **ansible** playbook for some more fine tuning. -2. Test your set up to make sure that everything has installed correctly. -3. Create some python environments. +1. Download and run a second **ansible** playbook for some more fine tuning +2. Test your set up to make sure that everything has installed correctly +3. Create isolated python environments for all your challenges Don't worry, we'll go into more detail in each of the individual sections. diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index daa3c03..8e37aea 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -118,7 +118,7 @@ terraform plan ``` $LINUX_END -And check the output, if you have any errors, raise a ticket with a teacher. +โ— And check the output, if you have any errors, raise a ticket with a teacher. If everything was successful, create your VM with: diff --git a/_partials/ubuntu_ansible_part1.md b/_partials/ubuntu_ansible_part1.md index ff41a31..aa0ecae 100644 --- a/_partials/ubuntu_ansible_part1.md +++ b/_partials/ubuntu_ansible_part1.md @@ -10,7 +10,7 @@ ansible --version You should get an output similar to (some version numbers might change, that's fine): -```bash +``` ansible [core 2.17.9] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] @@ -66,4 +66,4 @@ Once the playbook has finished running. Kill your terminal (little trash can at ![](/images/vscode_after_ansible1.png) -Your terminal should be `zsh`. +The terminal should read as `zsh`. diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md index 988702e..29a2029 100644 --- a/_partials/vscode_ssh_connection.md +++ b/_partials/vscode_ssh_connection.md @@ -41,3 +41,15 @@ And you are connected! It should look similar too: Notice the connection in the very bottom-left corner of your VS Code window. It should have the Connection type (SSH), and the name of the host you are connected to. **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) + +
+Viewing your SSH Configuration + +If you want to view your SSH configuration: +1. Start by clicking the symbol in the bottom-left corner of VS Code +2. Click on **Connect to Host...** +3. Click on **Configure SSH Hosts...*** +4. Select the configuration file. Usually the file at the top of the list. +5. View your configuration file! You may need to edit this configuration if you change computers, or want to work on more than one computer during the bootcamp. + +
From 09ba1780a1f352a75af6e02813913ad95325a2f8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 16:10:46 +0000 Subject: [PATCH 27/44] setup guides generated --- LINUX.md | 38 +++++++++++++++++++++++++------------- WINDOWS.md | 38 +++++++++++++++++++++++++------------- macOS.md | 38 +++++++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 39 deletions(-) diff --git a/LINUX.md b/LINUX.md index dbf4848..d009c0e 100644 --- a/LINUX.md +++ b/LINUX.md @@ -6,9 +6,9 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: -This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. -- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! -- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! +This setup is largely automated with **Terraform** and **Ansible**. There are three main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses, databases and more! +- **Ansible** is used to configure linux machines with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! ## Part 1: Setup your local computer @@ -16,8 +16,8 @@ In this section you'll setup your local computer and create some accounts. It wi 1. Install some communication tools: Zoom, Slack 2. Create some accounts: Github, Google Cloud Platform (GCP) 3. Install Visual Studio Code (VS Code) -4. Install and authentication the GCP command line tool: `gcloud`. -5. Install **terraform** on your local computer. +4. Install and authentication the GCP command line tool: `gcloud` +5. Install **terraform** on your local computer 6. Create your virtual machine with **terraform** and connect to it with **VS Code**! ## Part 2: Configure your Virtual Machine Part 1 @@ -26,18 +26,18 @@ All parts of this section happen on your virtual machine. This section includes: 1. Authenticate your virtual machine with `gcloud` -2. Download and run an **ansible** playbook to partially configure your virtual machine. +2. Download and run an **ansible** playbook to partially configure your virtual machine 3. Login to the Github command line tool on your virtual machine -4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! +4. Copy the Le Wagon recommended **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! ## Part 3: Configure your Virtual Machine Part 2 All parts of this section happen on your virtual machine. In this section you will: -1. Download and run a second **ansible** playbook for some more fine tuning. -2. Test your set up to make sure that everything has installed correctly. -3. Create some python environments. +1. Download and run a second **ansible** playbook for some more fine tuning +2. Test your set up to make sure that everything has installed correctly +3. Create isolated python environments for all your challenges Don't worry, we'll go into more detail in each of the individual sections. @@ -518,7 +518,7 @@ terraform init terraform plan ``` -And check the output, if you have any errors, raise a ticket with a teacher. +โ— And check the output, if you have any errors, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -573,6 +573,18 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +
+Viewing your SSH Configuration + +If you want to view your SSH configuration: +1. Start by clicking the symbol in the bottom-left corner of VS Code +2. Click on **Connect to Host...** +3. Click on **Configure SSH Hosts...*** +4. Select the configuration file. Usually the file at the top of the list. +5. View your configuration file! You may need to edit this configuration if you change computers, or want to work on more than one computer during the bootcamp. + +
+ ## Google Authentication @@ -641,7 +653,7 @@ ansible --version You should get an output similar to (some version numbers might change, that's fine): -```bash +``` ansible [core 2.17.9] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] @@ -697,7 +709,7 @@ Once the playbook has finished running. Kill your terminal (little trash can at ![](/images/vscode_after_ansible1.png) -Your terminal should be `zsh`. +The terminal should read as `zsh`. ## GitHub CLI diff --git a/WINDOWS.md b/WINDOWS.md index bea4c0c..03df8a1 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -6,9 +6,9 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: -This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. -- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! -- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! +This setup is largely automated with **Terraform** and **Ansible**. There are three main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses, databases and more! +- **Ansible** is used to configure linux machines with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! ## Part 1: Setup your local computer @@ -16,8 +16,8 @@ In this section you'll setup your local computer and create some accounts. It wi 1. Install some communication tools: Zoom, Slack 2. Create some accounts: Github, Google Cloud Platform (GCP) 3. Install Visual Studio Code (VS Code) -4. Install and authentication the GCP command line tool: `gcloud`. -5. Install **terraform** on your local computer. +4. Install and authentication the GCP command line tool: `gcloud` +5. Install **terraform** on your local computer 6. Create your virtual machine with **terraform** and connect to it with **VS Code**! ## Part 2: Configure your Virtual Machine Part 1 @@ -26,18 +26,18 @@ All parts of this section happen on your virtual machine. This section includes: 1. Authenticate your virtual machine with `gcloud` -2. Download and run an **ansible** playbook to partially configure your virtual machine. +2. Download and run an **ansible** playbook to partially configure your virtual machine 3. Login to the Github command line tool on your virtual machine -4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! +4. Copy the Le Wagon recommended **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! ## Part 3: Configure your Virtual Machine Part 2 All parts of this section happen on your virtual machine. In this section you will: -1. Download and run a second **ansible** playbook for some more fine tuning. -2. Test your set up to make sure that everything has installed correctly. -3. Create some python environments. +1. Download and run a second **ansible** playbook for some more fine tuning +2. Test your set up to make sure that everything has installed correctly +3. Create isolated python environments for all your challenges Don't worry, we'll go into more detail in each of the individual sections. @@ -457,7 +457,7 @@ terraform init terraform plan ``` -And check the output, if you have any errors, raise a ticket with a teacher. +โ— And check the output, if you have any errors, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -512,6 +512,18 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +
+Viewing your SSH Configuration + +If you want to view your SSH configuration: +1. Start by clicking the symbol in the bottom-left corner of VS Code +2. Click on **Connect to Host...** +3. Click on **Configure SSH Hosts...*** +4. Select the configuration file. Usually the file at the top of the list. +5. View your configuration file! You may need to edit this configuration if you change computers, or want to work on more than one computer during the bootcamp. + +
+ ## Google Authentication @@ -580,7 +592,7 @@ ansible --version You should get an output similar to (some version numbers might change, that's fine): -```bash +``` ansible [core 2.17.9] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] @@ -636,7 +648,7 @@ Once the playbook has finished running. Kill your terminal (little trash can at ![](/images/vscode_after_ansible1.png) -Your terminal should be `zsh`. +The terminal should read as `zsh`. ## GitHub CLI diff --git a/macOS.md b/macOS.md index 4ef52a1..063830d 100644 --- a/macOS.md +++ b/macOS.md @@ -6,9 +6,9 @@ A part of the setup will be done on your **local machine** but most of the confi Please **read instructions carefully and execute all commands in the following order**. If you get stuck, don't hesitate to ask a teacher for help :raising_hand: -This setup is largely automated with **Terraform** and **Ansible**. There are four main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. -- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses! -- **Ansible** is used to configure linux servers with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! +This setup is largely automated with **Terraform** and **Ansible**. There are three main components to the setup! **Terraform** and **ansible** are _Infrastructure as Code_ tools. +- **Terraform** excels at creating and destroying cloud resources, like virtual machines, IP addresses, databases and more! +- **Ansible** is used to configure linux machines with specific settings and software. Perfect for fine-tuning the Virtual Machine you will be creating! ## Part 1: Setup your local computer @@ -16,8 +16,8 @@ In this section you'll setup your local computer and create some accounts. It wi 1. Install some communication tools: Zoom, Slack 2. Create some accounts: Github, Google Cloud Platform (GCP) 3. Install Visual Studio Code (VS Code) -4. Install and authentication the GCP command line tool: `gcloud`. -5. Install **terraform** on your local computer. +4. Install and authentication the GCP command line tool: `gcloud` +5. Install **terraform** on your local computer 6. Create your virtual machine with **terraform** and connect to it with **VS Code**! ## Part 2: Configure your Virtual Machine Part 1 @@ -26,18 +26,18 @@ All parts of this section happen on your virtual machine. This section includes: 1. Authenticate your virtual machine with `gcloud` -2. Download and run an **ansible** playbook to partially configure your virtual machine. +2. Download and run an **ansible** playbook to partially configure your virtual machine 3. Login to the Github command line tool on your virtual machine -4. Copy some Le Wagon **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! +4. Copy the Le Wagon recommended **dotfiles**. **Dotfiles** are settings that will enhance your terminal and developer experience! ## Part 3: Configure your Virtual Machine Part 2 All parts of this section happen on your virtual machine. In this section you will: -1. Download and run a second **ansible** playbook for some more fine tuning. -2. Test your set up to make sure that everything has installed correctly. -3. Create some python environments. +1. Download and run a second **ansible** playbook for some more fine tuning +2. Test your set up to make sure that everything has installed correctly +3. Create isolated python environments for all your challenges Don't worry, we'll go into more detail in each of the individual sections. @@ -533,7 +533,7 @@ terraform init terraform plan ``` -And check the output, if you have any errors, raise a ticket with a teacher. +โ— And check the output, if you have any errors, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -588,6 +588,18 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +
+Viewing your SSH Configuration + +If you want to view your SSH configuration: +1. Start by clicking the symbol in the bottom-left corner of VS Code +2. Click on **Connect to Host...** +3. Click on **Configure SSH Hosts...*** +4. Select the configuration file. Usually the file at the top of the list. +5. View your configuration file! You may need to edit this configuration if you change computers, or want to work on more than one computer during the bootcamp. + +
+ ## Google Authentication @@ -656,7 +668,7 @@ ansible --version You should get an output similar to (some version numbers might change, that's fine): -```bash +``` ansible [core 2.17.9] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/tswift/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] @@ -712,7 +724,7 @@ Once the playbook has finished running. Kill your terminal (little trash can at ![](/images/vscode_after_ansible1.png) -Your terminal should be `zsh`. +The terminal should read as `zsh`. ## GitHub CLI From 85806187e7990c287e68ffc833105a3a471311c9 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Wed, 19 Mar 2025 18:50:42 +0200 Subject: [PATCH 28/44] automation: updated local gcloud and local terraform for windows --- _partials/gcp_cli_setup.md | 6 +++++- _partials/terraform.md | 35 ++++++++++++++++++++++++++++++++--- _partials/terraform_vm.md | 12 ++++++++++-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/_partials/gcp_cli_setup.md b/_partials/gcp_cli_setup.md index e1e7c37..17e49c6 100644 --- a/_partials/gcp_cli_setup.md +++ b/_partials/gcp_cli_setup.md @@ -23,7 +23,11 @@ $WINDOWS_START To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). -Once it's finished downloading, launch the installer as administrator and follow the prompts. +Once it's finished downloading, launch the installer and follow the prompts. + +On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new command prompt and ask a series of questions like: +- **Do you want to log in?** - type `y` and hit enter and following the prompts +- **Select your region and zone?** - type `y` and hit enter and select the geographic **region** that is closest to you. Refer to the GCP Region and Zone documentation at this [link here ๐Ÿ”—](https://cloud.google.com/compute/docs/regions-zones). There may be multiple options for each **region**, denoted by `-a`, `-b`, or `-c`, it doesn't matter which one you choose. $WINDOWS_END $LINUX_START diff --git a/_partials/terraform.md b/_partials/terraform.md index 364ffda..d0e27c5 100644 --- a/_partials/terraform.md +++ b/_partials/terraform.md @@ -11,9 +11,38 @@ brew install hashicorp/tap/terraform ``` $MAC_END $WINDOWS_START -To install terraform, download the binary from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). +### Download -TODO: Unsure if anything needs to be added to PATH to get it to work +To install terraform, download the **zip archive** from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). + +โ— If you are using Windows 10 or 11, download the **AMD64** version (64 bit version). + +1. Using file explorer to go to the location you downloaded the **terraform zip archive** + +2. **Unzip** the archive and two files should appear: `terraform.exe` and `license.txt`. + +3. Copy `terraform.exe` + +4. Navigate to your home directory (`C:\Users\\`) and create a directory named **cli_apps** + +5. Paste `terraform.exe` in the **cli_apps** directory + +### Add terraform to PATH + +We need to manually add **Terraform** to the `PATH` environment variable. The `PATH` variable contains a list of directories that your computer looks in for programs that we run from the command prompt. + +To update your path: +1. Open Windows Search and search for: **Environment Variables** + +2. Click **Environment Variables** or **Edit environment variables for your account** + +3. Click **New** on to top right of this window + +4. Enter: `C:\Users\YOUR_USERNAME\cli_apps` - Make sure to replace `YOUR_USERNAME` with your computers user name. + +5. Click **Ok** to close the `Path` variable window, and click **Ok** again to close the Environment Variable window. + +6. Close **Command Prompt** and open it again $WINDOWS_END $LINUX_START Install some basic requirements: @@ -21,7 +50,7 @@ Install some basic requirements: sudo apt-get update && sudo apt-get install -y gnupg software-properties-common ``` -Terraform is not available to **apt** by default so we need to make it available. +Terraform is not available to **apt** by default, so we need to manually add the repository. ```bash wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index 8e37aea..a0b5894 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -76,7 +76,15 @@ We'll need to change some values in this file. Here's were you can find the requ - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. - **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. - **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. -- **instance_user:** in your terminal, run `whoami` and hit enter. +$MAC_START +- **instance_user:** in your terminal, run `whoami` +$MAC_END +$WINDOWS_START +- **instance_user:** in the command prompt, run `echo %username%` +$WINDOWS_END +$LINUX_START +- **instance_user:** in your terminal, run `whoami` +$LINUX_END After completing this file, it should look similar to: @@ -85,7 +93,7 @@ project_id = "wagon-bootcamp" region = "europe-west1" zone = "europe-west1-b" instance_name = "lw-de-vm-tswift" -instance_user = "taylorswift" # result of `whoami` +instance_user = "taylorswift" ``` Make sure to save the `terraform.tfvars` file and then run: From 8008b76bd2c8c4ed8b7a4a17bb20f7ab9f2c8662 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 19 Mar 2025 16:51:14 +0000 Subject: [PATCH 29/44] setup guides generated --- LINUX.md | 6 +++--- WINDOWS.md | 43 ++++++++++++++++++++++++++++++++++++++----- macOS.md | 4 ++-- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/LINUX.md b/LINUX.md index d009c0e..1b096ee 100644 --- a/LINUX.md +++ b/LINUX.md @@ -412,7 +412,7 @@ Install some basic requirements: sudo apt-get update && sudo apt-get install -y gnupg software-properties-common ``` -Terraform is not available to **apt** by default so we need to make it available. +Terraform is not available to **apt** by default, so we need to manually add the repository. ```bash wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ @@ -496,7 +496,7 @@ We'll need to change some values in this file. Here's were you can find the requ - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. - **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. - **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. -- **instance_user:** in your terminal, run `whoami` and hit enter. +- **instance_user:** in your terminal, run `whoami` After completing this file, it should look similar to: @@ -505,7 +505,7 @@ project_id = "wagon-bootcamp" region = "europe-west1" zone = "europe-west1-b" instance_name = "lw-de-vm-tswift" -instance_user = "taylorswift" # result of `whoami` +instance_user = "taylorswift" ``` Make sure to save the `terraform.tfvars` file and then run: diff --git a/WINDOWS.md b/WINDOWS.md index 03df8a1..bd89e67 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -316,7 +316,11 @@ The `gcloud` Command Line Interface (CLI) is used to communicate with Google Clo To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). -Once it's finished downloading, launch the installer as administrator and follow the prompts. +Once it's finished downloading, launch the installer and follow the prompts. + +On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new command prompt and ask a series of questions like: +- **Do you want to log in?** - type `y` and hit enter and following the prompts +- **Select your region and zone?** - type `y` and hit enter and select the geographic **region** that is closest to you. Refer to the GCP Region and Zone documentation at this [link here ๐Ÿ”—](https://cloud.google.com/compute/docs/regions-zones). There may be multiple options for each **region**, denoted by `-a`, `-b`, or `-c`, it doesn't matter which one you choose. To test your install, run the following in your terminal: @@ -368,9 +372,38 @@ Your active configuration is: [default] Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. -To install terraform, download the binary from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). +### Download + +To install terraform, download the **zip archive** from the Terraform install page at this [link here ๐Ÿ”—](https://developer.hashicorp.com/terraform/install). + +โ— If you are using Windows 10 or 11, download the **AMD64** version (64 bit version). + +1. Using file explorer to go to the location you downloaded the **terraform zip archive** + +2. **Unzip** the archive and two files should appear: `terraform.exe` and `license.txt`. + +3. Copy `terraform.exe` + +4. Navigate to your home directory (`C:\Users\\`) and create a directory named **cli_apps** + +5. Paste `terraform.exe` in the **cli_apps** directory + +### Add terraform to PATH + +We need to manually add **Terraform** to the `PATH` environment variable. The `PATH` variable contains a list of directories that your computer looks in for programs that we run from the command prompt. + +To update your path: +1. Open Windows Search and search for: **Environment Variables** + +2. Click **Environment Variables** or **Edit environment variables for your account** + +3. Click **New** on to top right of this window + +4. Enter: `C:\Users\YOUR_USERNAME\cli_apps` - Make sure to replace `YOUR_USERNAME` with your computers user name. + +5. Click **Ok** to close the `Path` variable window, and click **Ok** again to close the Environment Variable window. -TODO: Unsure if anything needs to be added to PATH to get it to work +6. Close **Command Prompt** and open it again Verify the installation with: @@ -435,7 +468,7 @@ We'll need to change some values in this file. Here's were you can find the requ - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. - **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. - **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. -- **instance_user:** in your terminal, run `whoami` and hit enter. +- **instance_user:** in the command prompt, run `echo %username%` After completing this file, it should look similar to: @@ -444,7 +477,7 @@ project_id = "wagon-bootcamp" region = "europe-west1" zone = "europe-west1-b" instance_name = "lw-de-vm-tswift" -instance_user = "taylorswift" # result of `whoami` +instance_user = "taylorswift" ``` Make sure to save the `terraform.tfvars` file and then run: diff --git a/macOS.md b/macOS.md index 063830d..bce8dac 100644 --- a/macOS.md +++ b/macOS.md @@ -511,7 +511,7 @@ We'll need to change some values in this file. Here's were you can find the requ - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. - **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. - **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. -- **instance_user:** in your terminal, run `whoami` and hit enter. +- **instance_user:** in your terminal, run `whoami` After completing this file, it should look similar to: @@ -520,7 +520,7 @@ project_id = "wagon-bootcamp" region = "europe-west1" zone = "europe-west1-b" instance_name = "lw-de-vm-tswift" -instance_user = "taylorswift" # result of `whoami` +instance_user = "taylorswift" ``` Make sure to save the `terraform.tfvars` file and then run: From ef4cb40a069d60c62b5892a7987703e8729fa436 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:02:17 +0200 Subject: [PATCH 30/44] automation: added more windows specific settings --- _partials/gcp_adc_auth.md | 10 ++--- _partials/gcp_cli_setup.md | 48 +++++++++++++++++------ _partials/terraform_vm.md | 63 +++++++++++++++++++----------- _partials/vscode_ssh_connection.md | 34 ++++++++++++++-- 4 files changed, 111 insertions(+), 44 deletions(-) diff --git a/_partials/gcp_adc_auth.md b/_partials/gcp_adc_auth.md index fb02ccc..17a6c0f 100644 --- a/_partials/gcp_adc_auth.md +++ b/_partials/gcp_adc_auth.md @@ -1,15 +1,11 @@ -## Google Authentication - -Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. - ### Application Default Credentials -Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. -To authenticate your Application Default Credentials, in your terminal run: +To authenticate your **Application Default Credentials**, in your terminal run: ```bash gcloud auth application-default login ``` -And follow the prompts. +And follow the prompts. It should open a web-page to login to your Google account. diff --git a/_partials/gcp_cli_setup.md b/_partials/gcp_cli_setup.md index 17e49c6..8e870a2 100644 --- a/_partials/gcp_cli_setup.md +++ b/_partials/gcp_cli_setup.md @@ -11,24 +11,51 @@ Install with `brew`: brew install --cask google-cloud-sdk ``` -Then you can: +Then install `gcloud` with: ```bash $(brew --prefix)/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/install.sh ``` -๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#) +To test your install, open a new terminal and run: + +```bash +gcloud --version +``` + +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#mac) $MAC_END $WINDOWS_START -To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). +To install, download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). -Once it's finished downloading, launch the installer and follow the prompts. +Once it's finished downloading, launch the installer and follow the prompts. You only need to install `gcloud` for the current user. + +On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new **Command Prompt** window and ask a series of questions like: +- **Do you want to log in?** - type `y` and hit enter and following the prompts. It should open a web-browser to log in to your Google account. +- **Pick cloud project to use** - Select your GCP Project ID that you want to connect with `gcloud` +- **Select your region and zone** - You can safely enter `n`. It's not important to us at the moment. + +Once you've completed the `gcloud` setup, close **Command Prompt** and re-open it, then run: + +```bash +gcloud config list +``` -On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new command prompt and ask a series of questions like: -- **Do you want to log in?** - type `y` and hit enter and following the prompts -- **Select your region and zone?** - type `y` and hit enter and select the geographic **region** that is closest to you. Refer to the GCP Region and Zone documentation at this [link here ๐Ÿ”—](https://cloud.google.com/compute/docs/regions-zones). There may be multiple options for each **region**, denoted by `-a`, `-b`, or `-c`, it doesn't matter which one you choose. +You should get an output similar to: +``` +[accessibility] +screen_reader = True/False # depends on install options +[core] +account = your_email@domain.com +disable_usage_reporting = True/False # depends on install options +project = your_gcp_project + +Your active configurations: [default] +``` + +Now `gcloud` is installed and authenticated ๐Ÿš€ $WINDOWS_END $LINUX_START Add the `APT` repository and install with: @@ -41,11 +68,10 @@ sudo apt-get update && sudo apt-get install google-cloud-sdk sudo apt-get install google-cloud-sdk-app-engine-python ``` -๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) -$LINUX_END - -To test your install, run the following in your terminal: +To test your install, open a new terminal and run: ```bash gcloud --version ``` +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) +$LINUX_END diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index a0b5894..e1d5127 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -1,21 +1,34 @@ ## Provisioning your Virtual Machine with Terraform +You can create Cloud Resources like Virtual Machines in different ways: +- Through the Google Cloud [Compute Engine Console ๐Ÿ”—](https://console.cloud.google.com/compute/overview) +- Using `gcloud` +- With **Infrastructure as Code** tools like Terraform + +We'll be creating our Virtual Machine with Terraform + We're almost at the point of creating your Virtual Machine. -The specifications of the machine you'll use for the bootcamp are: +The specifications of the Virtual Machine and Network Settings you'll use for the bootcamp are: - Operation System: Ubuntu 22.04 LTS -- CPU: 4 Virtual CPU cores +- CPU: 4 Virtual CPU cores (2 physical CPU cores) - RAM: 16 GB -- Storage: 100 GB -- Network: Static External IP address +- Storage (Persistent Disk): 100 GB balanced +- Static External IP address - so it's easier to login. ### Cost ๐Ÿ’ธ -Creating and running a Virtual Machine on Google Cloud Platform costs money. +Creating and running a Virtual Machine on Google Cloud Platform costs money! + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the _Linux and Bash_ challenge today ๐Ÿ˜Ž). + +โ— **The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$150 USD per month.** โ— -If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). +You can massively reduce the cost by only running the Virtual Machine when you use it. You will _NOT_ be charged for the vCPU's and RAM while the Virtual Machine is off! -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! +You will always pay for the Storage (equivalent of your hard-drive on your local computer). It's ~$10 USD per month for 100 GB. + +The rule of thumb is: if Google can rent the resource out to someone else when your not using it, you only pay for it when you are using the resource. That's why you don't pay for the CPU and RAM when you are not using it, Google can rent it out to someone else, but always pay for Storage, Google can't rent it out to someone else because it has your data on it. ### Download terraform files @@ -98,35 +111,33 @@ instance_user = "taylorswift" Make sure to save the `terraform.tfvars` file and then run: +``` $MAC_START -```bash cd ~/wagon-de-bootcamp - -terraform init - -terraform plan -``` $MAC_END $WINDOWS_START -```cmd cd %USERPROFILE%\wagon-de-bootcamp - -terraform init - -terraform plan -``` $WINDOWS_END $LINUX_START -```bash cd ~/wagon-de-bootcamp +$LINUX_END terraform init terraform plan ``` -$LINUX_END -โ— And check the output, if you have any errors, raise a ticket with a teacher. +And check the output. Towards the bottom there should be a line: + +``` +Plan: 2 to add, 0 to change, 0 to destroy +``` + +We'll be adding: +- A compute engine instance +- A static external IP address + +โ— If you have any errors, read the error and debug. If you need some help, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -134,4 +145,10 @@ If everything was successful, create your VM with: terraform apply -auto-approve ``` -And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. +It might take a while for Terraform to create the cloud resources. Once you see: + +``` +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` + +Your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md index 29a2029..16d5087 100644 --- a/_partials/vscode_ssh_connection.md +++ b/_partials/vscode_ssh_connection.md @@ -1,4 +1,6 @@ -### Virtual Machine connection +## Virtual Machine connection + +### Create SSH keys We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. @@ -8,7 +10,7 @@ To create the VS Code SSH configuration, run the following in your terminal: gcloud compute config-ssh ``` -You should get an output similar to: +`gcloud` may tell you it needs to create a directory to continue. Accept and you should get an output similar to: ```bash You should now be able to use ssh/scp with your instances. @@ -18,6 +20,30 @@ For example, try running: # $ ssh lw-de-vm-.. ``` +$WINDOWS_START +### SSH File Permissions + +Windows has strict permissions for SSH files by default, we need to alter some permissions on the SSH configuration that was created by `gcloud` so VS Code can read the files and manage the SSH connection. + +In Command Prompt run: + +```cmd +icacls %USERPROFILE%\.ssh\config /inheritence:r +icacls %USERPROFILE%\.ssh\config /grant:r %USERNAME%:(R) +icacls %USERPROFILE%\.ssh\config /grant:r SYSTEM:(R) +``` + +And: + +```cmd +icacls %USERPROFILE%\.ssh\google_compute_engine /inheritence:r +icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r %USERNAME%:(R) +icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r SYSTEM:(R) +``` +$WINDOWS_END + +### Connect with VS Code + To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) @@ -30,7 +56,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You may be asked to select the platform of the remote host, select **Linux**. You will then be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -42,6 +68,8 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! +
Viewing your SSH Configuration From 7190332632264bba6483f705c23422c49c1e5009 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:02:44 +0200 Subject: [PATCH 31/44] build.rb: added ADC creds to local setup --- build.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/build.rb b/build.rb index fd269b3..cc7d8fa 100755 --- a/build.rb +++ b/build.rb @@ -22,11 +22,12 @@ vscode_remote_ssh gcp_cli_setup gcp_cli_oauth + gcp_adc_auth terraform terraform_vm vscode_ssh_connection - gcp_adc_auth gcp_cli_oauth + gcp_adc_auth ubuntu_ansible_part1 setup/gh_cli dotfiles @@ -56,12 +57,12 @@ win_vscode vscode_remote_ssh gcp_cli_setup - gcp_cli_oauth + gcp_adc_auth terraform terraform_vm vscode_ssh_connection - gcp_adc_auth gcp_cli_oauth + gcp_adc_auth ubuntu_ansible_part1 setup/gh_cli dotfiles @@ -92,11 +93,12 @@ vscode_remote_ssh gcp_cli_setup gcp_cli_oauth + gcp_adc_auth terraform terraform_vm vscode_ssh_connection - gcp_adc_auth gcp_cli_oauth + gcp_adc_auth ubuntu_ansible_part1 setup/gh_cli dotfiles From 04e30ed05fd7c5413f1462cd29eada89d388e8b3 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:05:15 +0200 Subject: [PATCH 32/44] partials: small note on vm pre-installed software --- _partials/terraform_vm.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index e1d5127..68f6f36 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -16,6 +16,8 @@ The specifications of the Virtual Machine and Network Settings you'll use for th - Storage (Persistent Disk): 100 GB balanced - Static External IP address - so it's easier to login. +The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! + ### Cost ๐Ÿ’ธ Creating and running a Virtual Machine on Google Cloud Platform costs money! From 6edcad5750cce66580a1139c9a6c475e9f3e248c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 10:05:33 +0000 Subject: [PATCH 33/44] setup guides generated --- LINUX.md | 112 ++++++++++++++++++++++++----------- WINDOWS.md | 169 +++++++++++++++++++++++++++++++++-------------------- macOS.md | 115 +++++++++++++++++++++++++----------- 3 files changed, 266 insertions(+), 130 deletions(-) diff --git a/LINUX.md b/LINUX.md index 1b096ee..71386dc 100644 --- a/LINUX.md +++ b/LINUX.md @@ -356,13 +356,12 @@ sudo apt-get update && sudo apt-get install google-cloud-sdk sudo apt-get install google-cloud-sdk-app-engine-python ``` -๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) - -To test your install, run the following in your terminal: +To test your install, open a new terminal and run: ```bash gcloud --version ``` +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#deb) ### Authenticate gcloud @@ -403,6 +402,19 @@ Your active configuration is: [default] ``` +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your **Application Default Credentials**, in your terminal run: + +```bash +gcloud auth application-default login +``` + +And follow the prompts. It should open a web-page to login to your Google account. + + ## Terraform Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. @@ -446,22 +458,37 @@ terraform --version ## Provisioning your Virtual Machine with Terraform +You can create Cloud Resources like Virtual Machines in different ways: +- Through the Google Cloud [Compute Engine Console ๐Ÿ”—](https://console.cloud.google.com/compute/overview) +- Using `gcloud` +- With **Infrastructure as Code** tools like Terraform + +We'll be creating our Virtual Machine with Terraform + We're almost at the point of creating your Virtual Machine. -The specifications of the machine you'll use for the bootcamp are: +The specifications of the Virtual Machine and Network Settings you'll use for the bootcamp are: - Operation System: Ubuntu 22.04 LTS -- CPU: 4 Virtual CPU cores +- CPU: 4 Virtual CPU cores (2 physical CPU cores) - RAM: 16 GB -- Storage: 100 GB -- Network: Static External IP address +- Storage (Persistent Disk): 100 GB balanced +- Static External IP address - so it's easier to login. + +The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! ### Cost ๐Ÿ’ธ -Creating and running a Virtual Machine on Google Cloud Platform costs money. +Creating and running a Virtual Machine on Google Cloud Platform costs money! + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the _Linux and Bash_ challenge today ๐Ÿ˜Ž). + +โ— **The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$150 USD per month.** โ— + +You can massively reduce the cost by only running the Virtual Machine when you use it. You will _NOT_ be charged for the vCPU's and RAM while the Virtual Machine is off! -If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). +You will always pay for the Storage (equivalent of your hard-drive on your local computer). It's ~$10 USD per month for 100 GB. -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! +The rule of thumb is: if Google can rent the resource out to someone else when your not using it, you only pay for it when you are using the resource. That's why you don't pay for the CPU and RAM when you are not using it, Google can rent it out to someone else, but always pay for Storage, Google can't rent it out to someone else because it has your data on it. ### Download terraform files @@ -510,7 +537,7 @@ instance_user = "taylorswift" Make sure to save the `terraform.tfvars` file and then run: -```bash +``` cd ~/wagon-de-bootcamp terraform init @@ -518,7 +545,17 @@ terraform init terraform plan ``` -โ— And check the output, if you have any errors, raise a ticket with a teacher. +And check the output. Towards the bottom there should be a line: + +``` +Plan: 2 to add, 0 to change, 0 to destroy +``` + +We'll be adding: +- A compute engine instance +- A static external IP address + +โ— If you have any errors, read the error and debug. If you need some help, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -526,10 +563,18 @@ If everything was successful, create your VM with: terraform apply -auto-approve ``` -And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. +It might take a while for Terraform to create the cloud resources. Once you see: + +``` +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` +Your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. -### Virtual Machine connection + +## Virtual Machine connection + +### Create SSH keys We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. @@ -539,7 +584,7 @@ To create the VS Code SSH configuration, run the following in your terminal: gcloud compute config-ssh ``` -You should get an output similar to: +`gcloud` may tell you it needs to create a directory to continue. Accept and you should get an output similar to: ```bash You should now be able to use ssh/scp with your instances. @@ -549,6 +594,9 @@ For example, try running: # $ ssh lw-de-vm-.. ``` + +### Connect with VS Code + To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) @@ -561,7 +609,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You may be asked to select the platform of the remote host, select **Linux**. You will then be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -573,6 +621,8 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! +
Viewing your SSH Configuration @@ -586,23 +636,6 @@ If you want to view your SSH configuration:
-## Google Authentication - -Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. - -### Application Default Credentials - -Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. - -To authenticate your Application Default Credentials, in your terminal run: - -```bash -gcloud auth application-default login -``` - -And follow the prompts. - - ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. @@ -641,6 +674,19 @@ Your active configuration is: [default] ``` +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your **Application Default Credentials**, in your terminal run: + +```bash +gcloud auth application-default login +``` + +And follow the prompts. It should open a web-page to login to your Google account. + + ## VM configuration with Ansible We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. diff --git a/WINDOWS.md b/WINDOWS.md index bd89e67..b11562a 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -314,58 +314,48 @@ The `gcloud` Command Line Interface (CLI) is used to communicate with Google Clo ### Install gcloud -To install download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). +To install, download the Google Cloud CLI installer from this [link here ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#windows). -Once it's finished downloading, launch the installer and follow the prompts. +Once it's finished downloading, launch the installer and follow the prompts. You only need to install `gcloud` for the current user. -On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new command prompt and ask a series of questions like: -- **Do you want to log in?** - type `y` and hit enter and following the prompts -- **Select your region and zone?** - type `y` and hit enter and select the geographic **region** that is closest to you. Refer to the GCP Region and Zone documentation at this [link here ๐Ÿ”—](https://cloud.google.com/compute/docs/regions-zones). There may be multiple options for each **region**, denoted by `-a`, `-b`, or `-c`, it doesn't matter which one you choose. +On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new **Command Prompt** window and ask a series of questions like: +- **Do you want to log in?** - type `y` and hit enter and following the prompts. It should open a web-browser to log in to your Google account. +- **Pick cloud project to use** - Select your GCP Project ID that you want to connect with `gcloud` +- **Select your region and zone** - You can safely enter `n`. It's not important to us at the moment. - -To test your install, run the following in your terminal: +Once you've completed the `gcloud` setup, close **Command Prompt** and re-open it, then run: ```bash -gcloud --version +gcloud config list ``` +You should get an output similar to: -### Authenticate gcloud - -We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. - -To authenticate `gcloud`, run: +``` +[accessibility] +screen_reader = True/False # depends on install options +[core] +account = your_email@domain.com +disable_usage_reporting = True/False # depends on install options +project = your_gcp_project -```bash -gcloud auth login +Your active configurations: [default] ``` -And following the prompts. For pasting into the terminal, your might need to use CTRL + SHIFT + V +Now `gcloud` is installed and authenticated ๐Ÿš€ -You also need to set the GCP project that your are working in. For this section, you'll need your GCP Project ID, which can be found on the GCP Console at this [link here](https://console.cloud.google.com). Makes sure you copy the _Project ID_ and **not** the _Project number_. -To set your project, replace `` with your GCP Project ID and run: +### Application Default Credentials -```bash -gcloud config set project -``` +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. -Confirm your setup with: +To authenticate your **Application Default Credentials**, in your terminal run: ```bash -gcloud config list -``` - -You should get an output similar to: - +gcloud auth application-default login ``` -[core] -account = taylorswift@domain.com # Should be your GCP email -disable_usage_reporting = True -project = my-gcp-project # Should be your GCP Project ID -Your active configuration is: [default] -``` +And follow the prompts. It should open a web-page to login to your Google account. ## Terraform @@ -414,22 +404,37 @@ terraform --version ## Provisioning your Virtual Machine with Terraform +You can create Cloud Resources like Virtual Machines in different ways: +- Through the Google Cloud [Compute Engine Console ๐Ÿ”—](https://console.cloud.google.com/compute/overview) +- Using `gcloud` +- With **Infrastructure as Code** tools like Terraform + +We'll be creating our Virtual Machine with Terraform + We're almost at the point of creating your Virtual Machine. -The specifications of the machine you'll use for the bootcamp are: +The specifications of the Virtual Machine and Network Settings you'll use for the bootcamp are: - Operation System: Ubuntu 22.04 LTS -- CPU: 4 Virtual CPU cores +- CPU: 4 Virtual CPU cores (2 physical CPU cores) - RAM: 16 GB -- Storage: 100 GB -- Network: Static External IP address +- Storage (Persistent Disk): 100 GB balanced +- Static External IP address - so it's easier to login. + +The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! ### Cost ๐Ÿ’ธ -Creating and running a Virtual Machine on Google Cloud Platform costs money. +Creating and running a Virtual Machine on Google Cloud Platform costs money! + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the _Linux and Bash_ challenge today ๐Ÿ˜Ž). + +โ— **The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$150 USD per month.** โ— + +You can massively reduce the cost by only running the Virtual Machine when you use it. You will _NOT_ be charged for the vCPU's and RAM while the Virtual Machine is off! -If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). +You will always pay for the Storage (equivalent of your hard-drive on your local computer). It's ~$10 USD per month for 100 GB. -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! +The rule of thumb is: if Google can rent the resource out to someone else when your not using it, you only pay for it when you are using the resource. That's why you don't pay for the CPU and RAM when you are not using it, Google can rent it out to someone else, but always pay for Storage, Google can't rent it out to someone else because it has your data on it. ### Download terraform files @@ -482,7 +487,7 @@ instance_user = "taylorswift" Make sure to save the `terraform.tfvars` file and then run: -```cmd +``` cd %USERPROFILE%\wagon-de-bootcamp terraform init @@ -490,7 +495,17 @@ terraform init terraform plan ``` -โ— And check the output, if you have any errors, raise a ticket with a teacher. +And check the output. Towards the bottom there should be a line: + +``` +Plan: 2 to add, 0 to change, 0 to destroy +``` + +We'll be adding: +- A compute engine instance +- A static external IP address + +โ— If you have any errors, read the error and debug. If you need some help, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -498,10 +513,18 @@ If everything was successful, create your VM with: terraform apply -auto-approve ``` -And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. +It might take a while for Terraform to create the cloud resources. Once you see: + +``` +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` + +Your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. -### Virtual Machine connection +## Virtual Machine connection + +### Create SSH keys We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. @@ -511,7 +534,7 @@ To create the VS Code SSH configuration, run the following in your terminal: gcloud compute config-ssh ``` -You should get an output similar to: +`gcloud` may tell you it needs to create a directory to continue. Accept and you should get an output similar to: ```bash You should now be able to use ssh/scp with your instances. @@ -521,6 +544,28 @@ For example, try running: # $ ssh lw-de-vm-.. ``` +### SSH File Permissions + +Windows has strict permissions for SSH files by default, we need to alter some permissions on the SSH configuration that was created by `gcloud` so VS Code can read the files and manage the SSH connection. + +In Command Prompt run: + +```cmd +icacls %USERPROFILE%\.ssh\config /inheritence:r +icacls %USERPROFILE%\.ssh\config /grant:r %USERNAME%:(R) +icacls %USERPROFILE%\.ssh\config /grant:r SYSTEM:(R) +``` + +And: + +```cmd +icacls %USERPROFILE%\.ssh\google_compute_engine /inheritence:r +icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r %USERNAME%:(R) +icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r SYSTEM:(R) +``` + +### Connect with VS Code + To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) @@ -533,7 +578,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You may be asked to select the platform of the remote host, select **Linux**. You will then be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -545,6 +590,8 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! +
Viewing your SSH Configuration @@ -558,23 +605,6 @@ If you want to view your SSH configuration:
-## Google Authentication - -Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. - -### Application Default Credentials - -Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. - -To authenticate your Application Default Credentials, in your terminal run: - -```bash -gcloud auth application-default login -``` - -And follow the prompts. - - ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. @@ -613,6 +643,19 @@ Your active configuration is: [default] ``` +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your **Application Default Credentials**, in your terminal run: + +```bash +gcloud auth application-default login +``` + +And follow the prompts. It should open a web-page to login to your Google account. + + ## VM configuration with Ansible We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. diff --git a/macOS.md b/macOS.md index bce8dac..ebac958 100644 --- a/macOS.md +++ b/macOS.md @@ -388,20 +388,20 @@ Install with `brew`: brew install --cask google-cloud-sdk ``` -Then you can: +Then install `gcloud` with: ```bash $(brew --prefix)/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/install.sh ``` -๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#) - -To test your install, run the following in your terminal: +To test your install, open a new terminal and run: ```bash gcloud --version ``` +๐Ÿ‘‰ [Install documentation ๐Ÿ”—](https://cloud.google.com/sdk/docs/install#mac) + ### Authenticate gcloud @@ -441,6 +441,19 @@ Your active configuration is: [default] ``` +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your **Application Default Credentials**, in your terminal run: + +```bash +gcloud auth application-default login +``` + +And follow the prompts. It should open a web-page to login to your Google account. + + ## Terraform Terraform is a tool for infrastructure as code (IAC) to create (and destroy) resources to create in the cloud. @@ -461,22 +474,37 @@ terraform --version ## Provisioning your Virtual Machine with Terraform +You can create Cloud Resources like Virtual Machines in different ways: +- Through the Google Cloud [Compute Engine Console ๐Ÿ”—](https://console.cloud.google.com/compute/overview) +- Using `gcloud` +- With **Infrastructure as Code** tools like Terraform + +We'll be creating our Virtual Machine with Terraform + We're almost at the point of creating your Virtual Machine. -The specifications of the machine you'll use for the bootcamp are: +The specifications of the Virtual Machine and Network Settings you'll use for the bootcamp are: - Operation System: Ubuntu 22.04 LTS -- CPU: 4 Virtual CPU cores +- CPU: 4 Virtual CPU cores (2 physical CPU cores) - RAM: 16 GB -- Storage: 100 GB -- Network: Static External IP address +- Storage (Persistent Disk): 100 GB balanced +- Static External IP address - so it's easier to login. + +The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! ### Cost ๐Ÿ’ธ -Creating and running a Virtual Machine on Google Cloud Platform costs money. +Creating and running a Virtual Machine on Google Cloud Platform costs money! + +If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the _Linux and Bash_ challenge today ๐Ÿ˜Ž). + +โ— **The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$150 USD per month.** โ— + +You can massively reduce the cost by only running the Virtual Machine when you use it. You will _NOT_ be charged for the vCPU's and RAM while the Virtual Machine is off! -If you have created a new Google Cloud Platform account, the cost of the Virtual machine will be covered by the $300 USD credit for the first 90 days if you are diligent with turning off your Virtual Machine (or finish the auto shutdown challenge ๐Ÿ˜Ž). +You will always pay for the Storage (equivalent of your hard-drive on your local computer). It's ~$10 USD per month for 100 GB. -The cost of running a Virtual Machine with our configuration 24 hours a day, 7 days a week is ~$130 USD per month. You can massively reduce the cost by only running the Virtual Machine when you use it. You will not be charged for the CPU and RAM while the Virtual Machine is off! +The rule of thumb is: if Google can rent the resource out to someone else when your not using it, you only pay for it when you are using the resource. That's why you don't pay for the CPU and RAM when you are not using it, Google can rent it out to someone else, but always pay for Storage, Google can't rent it out to someone else because it has your data on it. ### Download terraform files @@ -525,7 +553,7 @@ instance_user = "taylorswift" Make sure to save the `terraform.tfvars` file and then run: -```bash +``` cd ~/wagon-de-bootcamp terraform init @@ -533,7 +561,17 @@ terraform init terraform plan ``` -โ— And check the output, if you have any errors, raise a ticket with a teacher. +And check the output. Towards the bottom there should be a line: + +``` +Plan: 2 to add, 0 to change, 0 to destroy +``` + +We'll be adding: +- A compute engine instance +- A static external IP address + +โ— If you have any errors, read the error and debug. If you need some help, raise a ticket with a teacher. If everything was successful, create your VM with: @@ -541,10 +579,18 @@ If everything was successful, create your VM with: terraform apply -auto-approve ``` -And your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. +It might take a while for Terraform to create the cloud resources. Once you see: + +``` +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` + +Your Virtual Machine should be up and running! Check the GCP Compute Engine console at this [link here](https://console.cloud.google.com/compute/instances) to confirm. + +## Virtual Machine connection -### Virtual Machine connection +### Create SSH keys We need to connect VS Code to our Virtual Machine in the cloud so you will only work on that machine during the bootcamp. We'll use the [Remote - SSH Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) that we previously installed. @@ -554,7 +600,7 @@ To create the VS Code SSH configuration, run the following in your terminal: gcloud compute config-ssh ``` -You should get an output similar to: +`gcloud` may tell you it needs to create a directory to continue. Accept and you should get an output similar to: ```bash You should now be able to use ssh/scp with your instances. @@ -564,6 +610,9 @@ For example, try running: # $ ssh lw-de-vm-.. ``` + +### Connect with VS Code + To connect to your Virtual Machine, click on the small symbol at the very bottom-left corner of VS Code: ![](/images/vscode_remote_highlight.png) @@ -576,7 +625,7 @@ Click on the name of your Virtual Machine: ![](/images/vscode_remote_hosts.png) -A new VS Code window will open. You will be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. +A new VS Code window will open. You may be asked to select the platform of the remote host, select **Linux**. You will then be asked to _fingerprint_ the connection. VS Code is asking if you trust the remote host you are trying to connect to. Hit enter to continue. ![](/images/vscode_remote_fingerprint.png) @@ -588,6 +637,8 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! +
Viewing your SSH Configuration @@ -601,23 +652,6 @@ If you want to view your SSH configuration:
-## Google Authentication - -Since we're now on a Virtual Machine, it is like a fresh, new computer, we need to re-authenticate some services with Google. Luckily for us, `gcloud` comes pre-installed. - -### Application Default Credentials - -Application Default Credentials are for authenticating our **code** (the Python ๐Ÿ code we will write in the future) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. - -To authenticate your Application Default Credentials, in your terminal run: - -```bash -gcloud auth application-default login -``` - -And follow the prompts. - - ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. @@ -656,6 +690,19 @@ Your active configuration is: [default] ``` +### Application Default Credentials + +Application Default Credentials are for authenticating our **code** (Terraform and Python ๐Ÿ) to interact with Google services and resources. It's a small distinction between `gcloud` and **code**, but an important one. + +To authenticate your **Application Default Credentials**, in your terminal run: + +```bash +gcloud auth application-default login +``` + +And follow the prompts. It should open a web-page to login to your Google account. + + ## VM configuration with Ansible We'll be using [Ansible](https://docs.ansible.com/ansible/latest/getting_started/introduction.html) to configure your Virtual Machine with some software, configurations, packages, and frameworks that you'll use in the bootcamp. From d8c372d4760c0f2e7b451e6c6f97196e7e68f2f6 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:32:24 +0200 Subject: [PATCH 34/44] altered order of restarting terminal to look zsh --- _partials/dotfiles_new_laptop.md | 7 +++++++ _partials/ubuntu_ansible_part1.md | 6 ------ _partials/ubuntu_ansible_part2.md | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/_partials/dotfiles_new_laptop.md b/_partials/dotfiles_new_laptop.md index 6fa9e3a..cc8021b 100644 --- a/_partials/dotfiles_new_laptop.md +++ b/_partials/dotfiles_new_laptop.md @@ -40,3 +40,10 @@ cd ~/code/$GITHUB_USERNAME/dotfiles && zsh git_setup.sh If you don't do that, Kitt won't be able to track your progress. ๐Ÿ’ก Select the `@users.noreply.github.com` address if you don't want your email to appear in public repositories you may contribute to.
+ + +Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. diff --git a/_partials/ubuntu_ansible_part1.md b/_partials/ubuntu_ansible_part1.md index aa0ecae..c622902 100644 --- a/_partials/ubuntu_ansible_part1.md +++ b/_partials/ubuntu_ansible_part1.md @@ -61,9 +61,3 @@ This playbook is installing a few things, while the playbook is running, let's g - Install the **GitHub CLI**: the CLI tool that we'll use to interact with your GitHub account directly from the terminal. The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. - -Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. diff --git a/_partials/ubuntu_ansible_part2.md b/_partials/ubuntu_ansible_part2.md index 60cb892..f17099c 100644 --- a/_partials/ubuntu_ansible_part2.md +++ b/_partials/ubuntu_ansible_part2.md @@ -17,7 +17,7 @@ cd ~/vm-ansible-setup ansible-playbook playbooks/setup_vm_part2.yml ``` -And the playbook should start running! +And the playbook should start running! If you're asked if you want VS Code to behave more like Sublime Text, click accept. โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. From 8fff1387df9bc00efdd001dc397622237e0ed91d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 10:38:14 +0000 Subject: [PATCH 35/44] setup guides generated --- LINUX.md | 22 +++++++++++++++------- WINDOWS.md | 22 +++++++++++++++------- macOS.md | 22 +++++++++++++++------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/LINUX.md b/LINUX.md index 71386dc..728fda3 100644 --- a/LINUX.md +++ b/LINUX.md @@ -751,12 +751,6 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - ## GitHub CLI @@ -904,6 +898,13 @@ you don't want your email to appear in public repositories you may contribute to +Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + OR
@@ -956,6 +957,13 @@ you don't want your email to appear in public repositories you may contribute to
+Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + ## VM configuration with Ansible - Part 2 ### Ansible Playbook 2 @@ -975,7 +983,7 @@ cd ~/vm-ansible-setup ansible-playbook playbooks/setup_vm_part2.yml ``` -And the playbook should start running! +And the playbook should start running! If you're asked if you want VS Code to behave more like Sublime Text, click accept. โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. diff --git a/WINDOWS.md b/WINDOWS.md index b11562a..352b2e0 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -720,12 +720,6 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - ## GitHub CLI @@ -873,6 +867,13 @@ you don't want your email to appear in public repositories you may contribute to +Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + OR
@@ -925,6 +926,13 @@ you don't want your email to appear in public repositories you may contribute to
+Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + ## VM configuration with Ansible - Part 2 ### Ansible Playbook 2 @@ -944,7 +952,7 @@ cd ~/vm-ansible-setup ansible-playbook playbooks/setup_vm_part2.yml ``` -And the playbook should start running! +And the playbook should start running! If you're asked if you want VS Code to behave more like Sublime Text, click accept. โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. diff --git a/macOS.md b/macOS.md index ebac958..d8bce5e 100644 --- a/macOS.md +++ b/macOS.md @@ -767,12 +767,6 @@ This playbook is installing a few things, while the playbook is running, let's g The playbook is also running checks to see if things are installed or not. This is so you can safely re-run the playbook without any problems. -Once the playbook has finished running. Kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - ## GitHub CLI @@ -920,6 +914,13 @@ you don't want your email to appear in public repositories you may contribute to +Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + OR
@@ -972,6 +973,13 @@ you don't want your email to appear in public repositories you may contribute to
+Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. + + ## VM configuration with Ansible - Part 2 ### Ansible Playbook 2 @@ -991,7 +999,7 @@ cd ~/vm-ansible-setup ansible-playbook playbooks/setup_vm_part2.yml ``` -And the playbook should start running! +And the playbook should start running! If you're asked if you want VS Code to behave more like Sublime Text, click accept. โ— If any errors occur, raise a ticket with a teacher. You can safely run the playbook again. From 22e703f8e7756cbf9254bbc1562a194d759f513f Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:42:54 +0200 Subject: [PATCH 36/44] added heading for when students are on the vm --- _partials/gcp_auth_vm_heading.md | 3 +++ _partials/terraform_vm.md | 2 -- _partials/vscode_ssh_connection.md | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 _partials/gcp_auth_vm_heading.md diff --git a/_partials/gcp_auth_vm_heading.md b/_partials/gcp_auth_vm_heading.md new file mode 100644 index 0000000..24060ce --- /dev/null +++ b/_partials/gcp_auth_vm_heading.md @@ -0,0 +1,3 @@ +## VM gcloud and Application Default Credentials + +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! Luckily for us, `gcloud` comes pre-installed on the virtual machine. diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index 68f6f36..e1d5127 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -16,8 +16,6 @@ The specifications of the Virtual Machine and Network Settings you'll use for th - Storage (Persistent Disk): 100 GB balanced - Static External IP address - so it's easier to login. -The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! - ### Cost ๐Ÿ’ธ Creating and running a Virtual Machine on Google Cloud Platform costs money! diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md index 16d5087..85fd42a 100644 --- a/_partials/vscode_ssh_connection.md +++ b/_partials/vscode_ssh_connection.md @@ -68,8 +68,6 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) -We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! -
Viewing your SSH Configuration From 67376bc66ed4d4d793ca817bc800cf57e2b00b24 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 12:43:09 +0200 Subject: [PATCH 37/44] added heading for VM gcloud auth --- build.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.rb b/build.rb index cc7d8fa..57ae724 100755 --- a/build.rb +++ b/build.rb @@ -26,6 +26,7 @@ terraform terraform_vm vscode_ssh_connection + gcp_auth_vm_heading gcp_cli_oauth gcp_adc_auth ubuntu_ansible_part1 @@ -61,6 +62,7 @@ terraform terraform_vm vscode_ssh_connection + gcp_auth_vm_heading gcp_cli_oauth gcp_adc_auth ubuntu_ansible_part1 @@ -97,6 +99,7 @@ terraform terraform_vm vscode_ssh_connection + gcp_auth_vm_heading gcp_cli_oauth gcp_adc_auth ubuntu_ansible_part1 From af68740febc28f2b44a1c8cc92f740e1b9b8d89a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 10:43:26 +0000 Subject: [PATCH 38/44] setup guides generated --- LINUX.md | 9 +++++---- WINDOWS.md | 9 +++++---- macOS.md | 9 +++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/LINUX.md b/LINUX.md index 728fda3..cf46b50 100644 --- a/LINUX.md +++ b/LINUX.md @@ -474,8 +474,6 @@ The specifications of the Virtual Machine and Network Settings you'll use for th - Storage (Persistent Disk): 100 GB balanced - Static External IP address - so it's easier to login. -The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! - ### Cost ๐Ÿ’ธ Creating and running a Virtual Machine on Google Cloud Platform costs money! @@ -621,8 +619,6 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) -We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! -
Viewing your SSH Configuration @@ -636,6 +632,11 @@ If you want to view your SSH configuration:
+## VM gcloud and Application Default Credentials + +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! Luckily for us, `gcloud` comes pre-installed on the virtual machine. + + ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. diff --git a/WINDOWS.md b/WINDOWS.md index 352b2e0..1866a31 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -420,8 +420,6 @@ The specifications of the Virtual Machine and Network Settings you'll use for th - Storage (Persistent Disk): 100 GB balanced - Static External IP address - so it's easier to login. -The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! - ### Cost ๐Ÿ’ธ Creating and running a Virtual Machine on Google Cloud Platform costs money! @@ -590,8 +588,6 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) -We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! -
Viewing your SSH Configuration @@ -605,6 +601,11 @@ If you want to view your SSH configuration:
+## VM gcloud and Application Default Credentials + +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! Luckily for us, `gcloud` comes pre-installed on the virtual machine. + + ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. diff --git a/macOS.md b/macOS.md index d8bce5e..09246fc 100644 --- a/macOS.md +++ b/macOS.md @@ -490,8 +490,6 @@ The specifications of the Virtual Machine and Network Settings you'll use for th - Storage (Persistent Disk): 100 GB balanced - Static External IP address - so it's easier to login. -The image that we are creating our VM from also has some useful GCP utilities pre-installed, like `gcloud`! - ### Cost ๐Ÿ’ธ Creating and running a Virtual Machine on Google Cloud Platform costs money! @@ -637,8 +635,6 @@ Notice the connection in the very bottom-left corner of your VS Code window. It **The setup of your local machine is over. All following commands will be run from within your ๐Ÿšจ virtual machine**๐Ÿšจ terminal (via VS Code) -We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! -
Viewing your SSH Configuration @@ -652,6 +648,11 @@ If you want to view your SSH configuration:
+## VM gcloud and Application Default Credentials + +We'll be doing some of the steps again, but that's because the virtual machine is a completely new computer! Luckily for us, `gcloud` comes pre-installed on the virtual machine. + + ### Authenticate gcloud We need to authenticate the `gcloud` CLI tool and set the project so it can interact with Google from the terminal. From 51974f1f3605ab673074c5dc61bafc8202c944c1 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 13:27:37 +0200 Subject: [PATCH 39/44] build.rb: added repo_overview partial --- build.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.rb b/build.rb index 57ae724..b5fba8d 100755 --- a/build.rb +++ b/build.rb @@ -38,6 +38,7 @@ dotfiles_new_laptop ubuntu_ansible_part2 ubuntu_vm_test + repo_overview dbeaver setup/kitt ].freeze @@ -74,6 +75,7 @@ dotfiles_new_laptop ubuntu_ansible_part2 ubuntu_vm_test + repo_overview dbeaver setup/kitt ].freeze @@ -111,6 +113,7 @@ dotfiles_new_laptop ubuntu_ansible_part2 ubuntu_vm_test + repo_overview dbeaver setup/kitt ] From 3e714c42b8cc9cc06afcb08b8b0bf0be55d05007 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 11:28:03 +0000 Subject: [PATCH 40/44] setup guides generated --- LINUX.md | 43 +++++++++++++++++++++++++++++++++++++++++++ WINDOWS.md | 43 +++++++++++++++++++++++++++++++++++++++++++ macOS.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/LINUX.md b/LINUX.md index cf46b50..90ded1a 100644 --- a/LINUX.md +++ b/LINUX.md @@ -1270,6 +1270,49 @@ Type `:quit` and hit enter to exit the spark-shell and continue. That's all the testing we'll do for now! +## Let's Make! + +Almost there! In the second ansible playbook, the `lewagon/data-engineering-challenges` repository was forked from Le Wagon to you. Let's review how it works. + +Our setup will look a bit like this: + +![](/images/repo_overview.png) + +This allows you to work on challenges, but if we push any changes to the content, you can still access them! + +Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! + +```bash +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v +``` + +Should return: + +``` +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` + +From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: + +- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) +- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) +- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder + +Let's make! + +```bash +make install +``` + +This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. + +โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ + + ## DBeaver diff --git a/WINDOWS.md b/WINDOWS.md index 1866a31..cb1be22 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -1239,6 +1239,49 @@ Type `:quit` and hit enter to exit the spark-shell and continue. That's all the testing we'll do for now! +## Let's Make! + +Almost there! In the second ansible playbook, the `lewagon/data-engineering-challenges` repository was forked from Le Wagon to you. Let's review how it works. + +Our setup will look a bit like this: + +![](/images/repo_overview.png) + +This allows you to work on challenges, but if we push any changes to the content, you can still access them! + +Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! + +```bash +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v +``` + +Should return: + +``` +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` + +From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: + +- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) +- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) +- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder + +Let's make! + +```bash +make install +``` + +This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. + +โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ + + ## DBeaver diff --git a/macOS.md b/macOS.md index 09246fc..a885a2f 100644 --- a/macOS.md +++ b/macOS.md @@ -1286,6 +1286,49 @@ Type `:quit` and hit enter to exit the spark-shell and continue. That's all the testing we'll do for now! +## Let's Make! + +Almost there! In the second ansible playbook, the `lewagon/data-engineering-challenges` repository was forked from Le Wagon to you. Let's review how it works. + +Our setup will look a bit like this: + +![](/images/repo_overview.png) + +This allows you to work on challenges, but if we push any changes to the content, you can still access them! + +Check your remotes match `origin` your data engineering challenges and `upstream` lewagon's! + +```bash +cd ~/code/$(gh api user | jq -r '.login')/data-engineering-challenges +git remote -v +``` + +Should return: + +``` +origin git@github.com:/data-engineering-challenges.git (fetch) +origin git@github.com:/data-engineering-challenges.git (push) +upstream git@github.com:lewagon/data-engineering-challenges.git (fetch) +upstream git@github.com:lewagon/data-engineering-challenges.git (push) +``` + +From challenge folder root **on the vm**, we'll run `make install`, which triggers 3 operations: + +- `make install-poetry`: `cd` inside each challenge folders, and `poetry install` inside each! (takes a while) +- `make allow-envrc`: allow direnv to execute inside each folder (otherwise you have to manually "allow" it) +- `make own-repo`: allows your user to be the linux "owner" of all files in this challenge folder + +Let's make! + +```bash +make install +``` + +This will take a while. You have time to grab a coffee โ˜•๏ธ, take a break, or start the next step while all your poetry environments are installing. + +โš ๏ธ If at the very end of this process you get a few errors like: `direnv: error .envrc file not found` or a Python version isn't available (relating to `Dask`) - that is normal and nothing to worry about ๐Ÿ‘Œ + + ## DBeaver From 1bdbc7b9eebe38a61ba30c0f052a3b1243463348 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 16:33:37 +0200 Subject: [PATCH 41/44] added emojis, fixed dotfiles terminal image asset placement, added more redundancy to windows instructions --- _partials/dotfiles_new_laptop.md | 7 ------- _partials/gcp_cli_oauth.md | 2 +- _partials/gcp_cli_setup.md | 2 +- _partials/terraform.md | 4 ++-- _partials/terraform_vm.md | 27 ++++++++++++++++++++++----- _partials/ubuntu_vm_test.md | 12 ++++++------ _partials/vscode_ssh_connection.md | 12 ++++++++++-- 7 files changed, 42 insertions(+), 24 deletions(-) diff --git a/_partials/dotfiles_new_laptop.md b/_partials/dotfiles_new_laptop.md index cc8021b..6fa9e3a 100644 --- a/_partials/dotfiles_new_laptop.md +++ b/_partials/dotfiles_new_laptop.md @@ -40,10 +40,3 @@ cd ~/code/$GITHUB_USERNAME/dotfiles && zsh git_setup.sh If you don't do that, Kitt won't be able to track your progress. ๐Ÿ’ก Select the `@users.noreply.github.com` address if you don't want your email to appear in public repositories you may contribute to.
- - -Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. diff --git a/_partials/gcp_cli_oauth.md b/_partials/gcp_cli_oauth.md index e4a5240..e5fa057 100644 --- a/_partials/gcp_cli_oauth.md +++ b/_partials/gcp_cli_oauth.md @@ -26,7 +26,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True diff --git a/_partials/gcp_cli_setup.md b/_partials/gcp_cli_setup.md index 8e870a2..05c83fd 100644 --- a/_partials/gcp_cli_setup.md +++ b/_partials/gcp_cli_setup.md @@ -31,7 +31,7 @@ To install, download the Google Cloud CLI installer from this [link here ๐Ÿ”—](h Once it's finished downloading, launch the installer and follow the prompts. You only need to install `gcloud` for the current user. -On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new **Command Prompt** window and ask a series of questions like: +On the last screen of the installer there will be four check boxes. Makes sure that the boxes for `Start Google SDK Shell` and `Run gcloud init to configure the Google Cloud CLI` are selected then click **Finish**. This should open a new **Command Prompt** window and ask a series of questions like: - **Do you want to log in?** - type `y` and hit enter and following the prompts. It should open a web-browser to log in to your Google account. - **Pick cloud project to use** - Select your GCP Project ID that you want to connect with `gcloud` - **Select your region and zone** - You can safely enter `n`. It's not important to us at the moment. diff --git a/_partials/terraform.md b/_partials/terraform.md index d0e27c5..63ad3b9 100644 --- a/_partials/terraform.md +++ b/_partials/terraform.md @@ -23,9 +23,9 @@ To install terraform, download the **zip archive** from the Terraform install pa 3. Copy `terraform.exe` -4. Navigate to your home directory (`C:\Users\\`) and create a directory named **cli_apps** +4. Navigate to your home directory (`C:\Users\\`) and create a directory named `cli_apps` -5. Paste `terraform.exe` in the **cli_apps** directory +5. Paste `terraform.exe` in the `cli_apps` directory ### Add terraform to PATH diff --git a/_partials/terraform_vm.md b/_partials/terraform_vm.md index e1d5127..e304621 100644 --- a/_partials/terraform_vm.md +++ b/_partials/terraform_vm.md @@ -49,14 +49,17 @@ $MAC_END $WINDOWS_START Using the Command Prompt (cmd), run the following: -TODO: Requires testing - ```cmd mkdir %USERPROFILE%\wagon-de-bootcamp + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\main.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\provider.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\variables.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\terraform.tfvars" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\.terraform.lock.hcl" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl ``` $WINDOWS_END @@ -74,7 +77,17 @@ $LINUX_END ### Set variables -Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: +$MAC_START +Open up the file `~/wagon-de-bootcamp/terraform.tfvars` in VS Code or any other code editor. +$MAC_END +$WINDOWS_START +Open up the file `C:\Users\\wagon-de-bootcamp\terraform.tfvars` in VS Code or any other code editor. +$WINDOWS_END +$LINUX_START +Open up the file `~/wagon-de-bootcamp/terraform.tfvars` in VS Code or any other code editor. +$LINUX_END + +It should look like: ```bash project_id = "" @@ -93,7 +106,7 @@ $MAC_START - **instance_user:** in your terminal, run `whoami` $MAC_END $WINDOWS_START -- **instance_user:** in the command prompt, run `echo %username%` +- **instance_user:** in Command Prompt, run `echo %username%` $WINDOWS_END $LINUX_START - **instance_user:** in your terminal, run `whoami` @@ -109,7 +122,7 @@ instance_name = "lw-de-vm-tswift" instance_user = "taylorswift" ``` -Make sure to save the `terraform.tfvars` file and then run: +Make sure to save the `terraform.tfvars` file, nagivate into the directory with the terraform files with: ``` $MAC_START @@ -121,7 +134,11 @@ $WINDOWS_END $LINUX_START cd ~/wagon-de-bootcamp $LINUX_END +``` +And initialise and test the files with: + +```bash terraform init terraform plan diff --git a/_partials/ubuntu_vm_test.md b/_partials/ubuntu_vm_test.md index c007473..fb019fe 100644 --- a/_partials/ubuntu_vm_test.md +++ b/_partials/ubuntu_vm_test.md @@ -6,7 +6,7 @@ We've used two ansible playbooks to configure our Virtual Machine. Let's run som #### Python -To test: +๐Ÿงช To test: ```bash python --version @@ -20,7 +20,7 @@ Python 3.12.8 #### Pyenv -To test: +๐Ÿงช To test: ```bash pyenv versions @@ -37,7 +37,7 @@ Note: There should be an `*` next to 3.12.8 #### Pipx -To test: +๐Ÿงช To test: ```bash pipx list @@ -60,7 +60,7 @@ manual pages are exposed at /home//.local/share/man #### Docker -To test: +๐Ÿงช To test: ```bash docker run hello-world @@ -167,7 +167,7 @@ Should return: #### Terraform -To test: +๐Ÿงช To test: ```bash terraform --version @@ -182,7 +182,7 @@ on linux_amd64 #### Spark -To test: +๐Ÿงช To test: ```bash spark-shell diff --git a/_partials/vscode_ssh_connection.md b/_partials/vscode_ssh_connection.md index 85fd42a..c2f671e 100644 --- a/_partials/vscode_ssh_connection.md +++ b/_partials/vscode_ssh_connection.md @@ -28,17 +28,25 @@ Windows has strict permissions for SSH files by default, we need to alter some p In Command Prompt run: ```cmd -icacls %USERPROFILE%\.ssh\config /inheritence:r +icacls %USERPROFILE%\.ssh\config /inheritance:r + icacls %USERPROFILE%\.ssh\config /grant:r %USERNAME%:(R) + icacls %USERPROFILE%\.ssh\config /grant:r SYSTEM:(R) + +icacls %USERPROFILE%\.ssh\config ``` And: ```cmd -icacls %USERPROFILE%\.ssh\google_compute_engine /inheritence:r +icacls %USERPROFILE%\.ssh\google_compute_engine /inheritance:r + icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r %USERNAME%:(R) + icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r SYSTEM:(R) + +icacls %USERPROFILE%\.ssh\google_compute_engine ``` $WINDOWS_END From fc4abd363ab2a5490ba8c197a4cbb6fc6a7ecefd Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 16:33:57 +0200 Subject: [PATCH 42/44] split out what the terminal should look like after lw dotfiles --- _partials/dotfiles_terminal.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 _partials/dotfiles_terminal.md diff --git a/_partials/dotfiles_terminal.md b/_partials/dotfiles_terminal.md new file mode 100644 index 0000000..062d588 --- /dev/null +++ b/_partials/dotfiles_terminal.md @@ -0,0 +1,7 @@ +--- + +Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: + +![](/images/vscode_after_ansible1.png) + +The terminal should read as `zsh`. From 668ab3d1f31f9f7cc8995f8a92b2cf257de95b69 Mon Sep 17 00:00:00 2001 From: Lorcan Rae Date: Thu, 20 Mar 2025 16:34:38 +0200 Subject: [PATCH 43/44] updated build.rb --- build.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.rb b/build.rb index b5fba8d..692b640 100755 --- a/build.rb +++ b/build.rb @@ -36,6 +36,7 @@ dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop + dotfiles_terminal ubuntu_ansible_part2 ubuntu_vm_test repo_overview @@ -73,6 +74,7 @@ dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop + dotfiles_terminal ubuntu_ansible_part2 ubuntu_vm_test repo_overview @@ -111,6 +113,7 @@ dotfiles_new_laptop dotfiles_new_laptop_heading dotfiles_new_laptop + dotfiles_terminal ubuntu_ansible_part2 ubuntu_vm_test repo_overview From 6d5402d269fe80cf27de786d820b943a468827ba Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 14:34:58 +0000 Subject: [PATCH 44/44] setup guides generated --- LINUX.md | 35 +++++++++++++++---------------- WINDOWS.md | 60 ++++++++++++++++++++++++++++++++---------------------- macOS.md | 35 +++++++++++++++---------------- 3 files changed, 72 insertions(+), 58 deletions(-) diff --git a/LINUX.md b/LINUX.md index 90ded1a..1b607e8 100644 --- a/LINUX.md +++ b/LINUX.md @@ -392,7 +392,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -506,7 +506,9 @@ curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent ### Set variables -Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: +Open up the file `~/wagon-de-bootcamp/terraform.tfvars` in VS Code or any other code editor. + +It should look like: ```bash project_id = "" @@ -533,11 +535,15 @@ instance_name = "lw-de-vm-tswift" instance_user = "taylorswift" ``` -Make sure to save the `terraform.tfvars` file and then run: +Make sure to save the `terraform.tfvars` file, nagivate into the directory with the terraform files with: ``` cd ~/wagon-de-bootcamp +``` +And initialise and test the files with: + +```bash terraform init terraform plan @@ -665,7 +671,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -899,13 +905,6 @@ you don't want your email to appear in public repositories you may contribute to -Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - - OR
@@ -958,6 +957,8 @@ you don't want your email to appear in public repositories you may contribute to
+--- + Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) @@ -1060,7 +1061,7 @@ We've used two ansible playbooks to configure our Virtual Machine. Let's run som #### Python -To test: +๐Ÿงช To test: ```bash python --version @@ -1074,7 +1075,7 @@ Python 3.12.8 #### Pyenv -To test: +๐Ÿงช To test: ```bash pyenv versions @@ -1091,7 +1092,7 @@ Note: There should be an `*` next to 3.12.8 #### Pipx -To test: +๐Ÿงช To test: ```bash pipx list @@ -1114,7 +1115,7 @@ manual pages are exposed at /home//.local/share/man #### Docker -To test: +๐Ÿงช To test: ```bash docker run hello-world @@ -1221,7 +1222,7 @@ Should return: #### Terraform -To test: +๐Ÿงช To test: ```bash terraform --version @@ -1236,7 +1237,7 @@ on linux_amd64 #### Spark -To test: +๐Ÿงช To test: ```bash spark-shell diff --git a/WINDOWS.md b/WINDOWS.md index cb1be22..f012d81 100644 --- a/WINDOWS.md +++ b/WINDOWS.md @@ -318,7 +318,7 @@ To install, download the Google Cloud CLI installer from this [link here ๐Ÿ”—](h Once it's finished downloading, launch the installer and follow the prompts. You only need to install `gcloud` for the current user. -On the last screen of the installer there will be four check boxes. Makes sure that the box for `run gcloud init` is selected. On confirmation this should open a new **Command Prompt** window and ask a series of questions like: +On the last screen of the installer there will be four check boxes. Makes sure that the boxes for `Start Google SDK Shell` and `Run gcloud init to configure the Google Cloud CLI` are selected then click **Finish**. This should open a new **Command Prompt** window and ask a series of questions like: - **Do you want to log in?** - type `y` and hit enter and following the prompts. It should open a web-browser to log in to your Google account. - **Pick cloud project to use** - Select your GCP Project ID that you want to connect with `gcloud` - **Select your region and zone** - You can safely enter `n`. It's not important to us at the moment. @@ -374,9 +374,9 @@ To install terraform, download the **zip archive** from the Terraform install pa 3. Copy `terraform.exe` -4. Navigate to your home directory (`C:\Users\\`) and create a directory named **cli_apps** +4. Navigate to your home directory (`C:\Users\\`) and create a directory named `cli_apps` -5. Paste `terraform.exe` in the **cli_apps** directory +5. Paste `terraform.exe` in the `cli_apps` directory ### Add terraform to PATH @@ -442,21 +442,26 @@ First we'll create a folder and download the terraform files with: Using the Command Prompt (cmd), run the following: -TODO: Requires testing - ```cmd mkdir %USERPROFILE%\wagon-de-bootcamp + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\main.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/main.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\provider.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/provider.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\variables.tf" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/variables.tf + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\terraform.tfvars" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/terraform.tfvars + curl -L -o "%USERPROFILE%\wagon-de-bootcamp\.terraform.lock.hcl" https://raw.githubusercontent.com/lewagon/data-engineering-setup/lorcanrae/automated-setup/automation/infra/.terraform.lock.hcl ``` ### Set variables -Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: +Open up the file `C:\Users\\wagon-de-bootcamp\terraform.tfvars` in VS Code or any other code editor. + +It should look like: ```bash project_id = "" @@ -471,7 +476,7 @@ We'll need to change some values in this file. Here's were you can find the requ - **region:** take a look at the GCP Region and Zone documentation at this [link here](https://cloud.google.com/compute/docs/regions-zones). We strongly recommend you choose the closest geographical region. - **zone:** Zone is a subset of region. it is almost always the same as **region** appended with `-a`, `-b`, or `-c`. - **instance_name:** we recommend naming your VM: `lw-de-vm-`. Replacing `` with your GitHub username. -- **instance_user:** in the command prompt, run `echo %username%` +- **instance_user:** in Command Prompt, run `echo %username%` After completing this file, it should look similar to: @@ -483,11 +488,15 @@ instance_name = "lw-de-vm-tswift" instance_user = "taylorswift" ``` -Make sure to save the `terraform.tfvars` file and then run: +Make sure to save the `terraform.tfvars` file, nagivate into the directory with the terraform files with: ``` cd %USERPROFILE%\wagon-de-bootcamp +``` + +And initialise and test the files with: +```bash terraform init terraform plan @@ -549,17 +558,25 @@ Windows has strict permissions for SSH files by default, we need to alter some p In Command Prompt run: ```cmd -icacls %USERPROFILE%\.ssh\config /inheritence:r +icacls %USERPROFILE%\.ssh\config /inheritance:r + icacls %USERPROFILE%\.ssh\config /grant:r %USERNAME%:(R) + icacls %USERPROFILE%\.ssh\config /grant:r SYSTEM:(R) + +icacls %USERPROFILE%\.ssh\config ``` And: ```cmd -icacls %USERPROFILE%\.ssh\google_compute_engine /inheritence:r +icacls %USERPROFILE%\.ssh\google_compute_engine /inheritance:r + icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r %USERNAME%:(R) + icacls %USERPROFILE%\.ssh\google_compute_engine /grant:r SYSTEM:(R) + +icacls %USERPROFILE%\.ssh\google_compute_engine ``` ### Connect with VS Code @@ -634,7 +651,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -868,13 +885,6 @@ you don't want your email to appear in public repositories you may contribute to -Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - - OR
@@ -927,6 +937,8 @@ you don't want your email to appear in public repositories you may contribute to
+--- + Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) @@ -1029,7 +1041,7 @@ We've used two ansible playbooks to configure our Virtual Machine. Let's run som #### Python -To test: +๐Ÿงช To test: ```bash python --version @@ -1043,7 +1055,7 @@ Python 3.12.8 #### Pyenv -To test: +๐Ÿงช To test: ```bash pyenv versions @@ -1060,7 +1072,7 @@ Note: There should be an `*` next to 3.12.8 #### Pipx -To test: +๐Ÿงช To test: ```bash pipx list @@ -1083,7 +1095,7 @@ manual pages are exposed at /home//.local/share/man #### Docker -To test: +๐Ÿงช To test: ```bash docker run hello-world @@ -1190,7 +1202,7 @@ Should return: #### Terraform -To test: +๐Ÿงช To test: ```bash terraform --version @@ -1205,7 +1217,7 @@ on linux_amd64 #### Spark -To test: +๐Ÿงช To test: ```bash spark-shell diff --git a/macOS.md b/macOS.md index a885a2f..f003c70 100644 --- a/macOS.md +++ b/macOS.md @@ -431,7 +431,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -522,7 +522,9 @@ curl -L -o ~/wagon-de-bootcamp/.terraform.lock.hcl https://raw.githubusercontent ### Set variables -Open up the file `terraform.tfvars` in VS Code or any other code editor. It should look like: +Open up the file `~/wagon-de-bootcamp/terraform.tfvars` in VS Code or any other code editor. + +It should look like: ```bash project_id = "" @@ -549,11 +551,15 @@ instance_name = "lw-de-vm-tswift" instance_user = "taylorswift" ``` -Make sure to save the `terraform.tfvars` file and then run: +Make sure to save the `terraform.tfvars` file, nagivate into the directory with the terraform files with: ``` cd ~/wagon-de-bootcamp +``` +And initialise and test the files with: + +```bash terraform init terraform plan @@ -681,7 +687,7 @@ gcloud config list You should get an output similar to: -``` +```bash [core] account = taylorswift@domain.com # Should be your GCP email disable_usage_reporting = True @@ -915,13 +921,6 @@ you don't want your email to appear in public repositories you may contribute to -Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: - -![](/images/vscode_after_ansible1.png) - -The terminal should read as `zsh`. - - OR
@@ -974,6 +973,8 @@ you don't want your email to appear in public repositories you may contribute to
+--- + Once you have finished installing the **dotfiles**, kill your terminal (little trash can at the top right of the terminal window) and re-open it. You might have to do it a few times until it looks similar to: ![](/images/vscode_after_ansible1.png) @@ -1076,7 +1077,7 @@ We've used two ansible playbooks to configure our Virtual Machine. Let's run som #### Python -To test: +๐Ÿงช To test: ```bash python --version @@ -1090,7 +1091,7 @@ Python 3.12.8 #### Pyenv -To test: +๐Ÿงช To test: ```bash pyenv versions @@ -1107,7 +1108,7 @@ Note: There should be an `*` next to 3.12.8 #### Pipx -To test: +๐Ÿงช To test: ```bash pipx list @@ -1130,7 +1131,7 @@ manual pages are exposed at /home//.local/share/man #### Docker -To test: +๐Ÿงช To test: ```bash docker run hello-world @@ -1237,7 +1238,7 @@ Should return: #### Terraform -To test: +๐Ÿงช To test: ```bash terraform --version @@ -1252,7 +1253,7 @@ on linux_amd64 #### Spark -To test: +๐Ÿงช To test: ```bash spark-shell

RAsAc=+ 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 ZAC|p$baBnHe(*`b%Zj0Vvf1Pn{|88q#MS@+ literal 0 HcmV?d00001 diff --git a/images/vscode_after_ansible1.png b/images/vscode_after_ansible1.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3cb2cbe2d0c7b82c81dd0a585b462e08abffe7 GIT binary patch literal 36018 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