☁️
Cloud Computing 2025 - SIMPRE
  • Cloud Computing 2025- SIMPRE
  • Cerințe proiect
  • Resurse utile
  • 1️Seminar 1
    • Configurarea mediului de dezvoltare
    • Crearea și clonarea unui GitHub Repository
    • Crearea proiectului de NextJS
    • Set-up Cloud Storage MongoDB
    • Set-up MongoDB in NextJS
  • 2️Seminar 2
    • Implementare interfață utilizator
    • Deploy Vercel
    • ChatGPT Chatbot
  • 3️Seminar 3
    • Amazon Web Services (AWS)
    • Securizare cont AWS
    • Oprirea proceselor
Powered by GitBook
On this page
  • 1. Crearea unei instanțe EC2
  • 2. Crearea și alocarea unui Elastic IP
  • 3. Conectarea la instanță EC2 prin cheia SSH
  • 4. Configurarea instanței EC2
  • 4.1. Actualizarea pachetelor
  • 4.2. Instalare Nginx
  • 4.3. Modificare configurare Nginx
  • 4.4. Instalare Docker
  • 4.5. Alocare drepturi folosire comenzi Docker fără sudo
  • 4.6. Pregătirea proiectului pentru a fi introdus într-o imagine Docker
  • 4.7. Clonarea proiectului de pe GitHub pe instanța de AWS
  • 4.8. Actualizarea codului pe instanță
  • 5. Oprirea instanței
  • 6. Pornirea instanței
  1. Seminar 3

Amazon Web Services (AWS)

PreviousChatGPT ChatbotNextSecurizare cont AWS

Last updated 1 year ago

Amazon Web Services este unul dintre ce mai mari furnizori de servicii în Cloud, care însumează acum peste 200 de servicii.

Unul dintre cele mai utilizate servicii este EC2 (Elastic Compute Cloud) care pune la dispoziție mașini virtuale. Scopul nostru este de a porni o astfel de masină virtuală, a ne conecta la ea și a face disponibilă aplicația creată în pașii anteriori către internet.

1. Crearea unei instanțe EC2

Primul pas este reprezentat de crearea unui cont de AWS:

Instanța EC2 (Elastic Compute Cloud) pe AWS este o mașină virtuală scalabilă și configurabilă pe care o putem lansa în cloud-ul Amazon Web Services pentru a rula aplicații și servicii.

După autentificare, mergem la secțiunea search și căutăm EC2.

Ulterior, o să alegem să creăm o nouă instanță, apăsând butonul 'Launch Instance'.

Este foarte important să aveți grijă în ce zonă geografică vă creați instanța, deoarece dacă o să o schimbați vreodată din greșeală, nu o să vă mai puteți vedea instanțele până câ o să vă întoarceți la zona inițială.

Ulterior, trebuie să trecem printr-o serie de pași:

  1. Alegem un nume

  2. Alegem o masină virtuală Ubuntu

  3. La tipul de instanță, o să îl lăsăm pe care care vine default și care este gratuit (t3.micro)

  4. Să alegem o cheie SSH existentă sau generarea unei chei noi și salvarea acesteia într-un loc dedicat pe computer

  5. Permiterea traficului HTTPS

În cazul în care dorim să alegem un alt tip de instanță, în afară de t3.micro, AWS vă va taxa taxa atâta timp cât instanța este pornită și rulează.

După crearea instanței, ar trebui să putem vedea următorul mesaj:

2. Crearea și alocarea unui Elastic IP

Atunci când creăm o nouă instanță pe care o să o tot oprim și să o pornim la loc, IP-ul instanței o să se tot schimbe.

Putem preveni acest lucru prin crearea unui IP care să nu se schimbe (Elastic IP).

Elastic IP-ul poate genera costuri suplimentare.

Mergem înapoi la secțiunea search și căutăm elastic IP.

Apăsăm pe butonul 'Allocate Elastic IP address' (lăsăm configurările default și apăsăm Allocate).

După crearea elastic IP-ului, urmează etapa în care trebuie să asociem acest elastic IP insanței pe care abia am creat-o. Apăsăm pe ip-ul creat, apoi pe butonul Allocate Elastic IP Address.

3. Conectarea la instanță EC2 prin cheia SSH

Deschidem un terminal de Git și navigăm până la locul unde am salvat cheia SSH.

Comandă conenctare SSH:

ssh -i <KEY_NAME>.pem ubuntu@<ELASTIC_IP>

Pentru că este prima dată când ne conectăm, cel mai probabil o să fim întrebați dacă sigur dorim să continuăm conectarea, deoarece cheia este necunoscută.

4. Configurarea instanței EC2

4.1. Actualizarea pachetelor

Rulăm pe rând următoarele comenzi:

sudo apt update
sudo apt upgrade

4.2. Instalare Nginx

Nginx este un server web de performanță ridicată și proxy invers, folosit pentru gestionarea traficului web și pentru servirea conținutului static și dinamic.

Rulăm pe rând următoarele comenzi:

sudo apt install nginx
sudo service nginx start

Acum, accesăm serverul la adresa IP pe care am generat-o anterior, și ar trebui să observăm un mesaj de bun venit.

4.3. Modificare configurare Nginx

Rulăm prima comandă pentru a accesa fisierul de configurare nginx:

sudo nano /etc/nginx/sites-available/default

Ștergem tot conținutul fișierului (CTRL + K de mai multe ori) și îl înlocuim cu următorul cod:

server {
        location / {
                proxy_pass http://localhost:3000/;
        }
}

Apăsăm CTRL + S ca să salvăm fișierul și CTRL + X ca să ieșim din fișier.

Penrtru a reînărca fișierul de configurare nginx, o să îi dăm reload:

sudo service nginx reload

Astfel vom indica faptul că ne dorim ca serverul nostru să afișeze aplicația care va rula pe portul 3000.

Dacă o să încercăm să mergem acum din nou la adresa IP, o să primi eroarea 502, dar urmează să o fixăm imediat.

4.4. Instalare Docker

Pentru a fi siguri că nu uitam o comandă, le voi lista și în această documentație.

Rulăm pe rând următoarele comenzi:

sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
apt-cache policy docker-ce
sudo apt install docker-ce
sudo systemctl status docker

Dacă totul a fost în regulă, ar trebui să putem vedea următorul mesaj în consolă:

CTRL + C ca să ieșim.

4.5. Alocare drepturi folosire comenzi Docker fără sudo

Înainte de a asigura acces sudo pentru comenzile docker, va trebui să adaugăm o parolă pentru userul ubuntu (creat de AWS la pornirea instanței EC2).

Rulăm pe rând următoarele comenzi:

sudo su -
passwd ubuntu

Salvați parola într-un fișier local pe calculator, sau în fișierul de .env

Acum, trebuie să ne întoarcem la utilizatorul ubuntu, folosind comanda:

su -l ubuntu

Acum putem asigura acces sudo pentru comenzile docker:

sudo usermod -aG docker ${USER}
su - ${USER}

Urmază pasul în care introducem parola, după care putem folosi comanda docker pentru utilizatorul ubuntu, fără să mai folosim sudo.

Putem testa acest lucru, folosind comanda:

docker images

4.6. Pregătirea proiectului pentru a fi introdus într-o imagine Docker

Modificăm fișierul next.config.js pentru a indica faptul că pregătim proiectul pentru a fi trimis în producție. Inserăm linia output: "standalone".

// /next.config.mjs

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  output: "standalone",
};

export default nextConfig;

Urmează pasul în care o să creăm un fișier Dockerfile în root-ul proiectului și o să dăm copy paste la codul de mai jos, luat de pe documentația oficială Vercel.

// /Dockerfile

FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN yarn build

# If using npm comment out above and use below instead
# RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

Urmează să creăm și un fișier de .dockerignore în root-ul proiectului, astfel încât să poată ignora anumite fișiere. Denumire fișierului trebuie să fie exactă, și anume .dockerignore.

// .dockerignore

Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git

La sfărșit, urcăm totul pe GitHub.

4.7. Clonarea proiectului de pe GitHub pe instanța de AWS

Înapoi în consola instanței EC2 configurate, o să aducem proiectul NextJS cu ajutorul Git. Pentru aceasta, avem nevoie de link-ul de clonare al repository-ului nostru, pe care îl vom lua de pe GitHub, exact ca la început când ne-am clonat repository-ul local.

Ne întoarcem pe consola de la AWS, și tastăm următoarea comandă:

git clone <LINK>

După clonare, putem folosi comanda ls pentru a vedea toate directoarele și pentru a observa dacă repository-ul s-a clonat cu succes sau nu.

Ca și următori pași, urmează să ne mutăm în cadrul directorului abia clonat, și să ne creăm fișierul cu chei de environment.

cd CloundComputing

Pentru crearea unui nou fișier, o să folosim comanda touch:

touch .env

Pentru editarea fișierului, o să folosim comanda nano, și o să copiem conținutul fișierului .env pe care îl avem local în proiectul nostru:

sudo nano .env

Pentru salvarea fișierului, o să folosim CTRL + X, Y și ENTER.

Pentru a face build aplicației și pentru a muta tot codul într-o imagine de Docker, o să folosim următoarea comandă:

docker build -t nextjs-docker .

Pentru a testa că totul a funcționat, o să rulăm următoarea comandă

docker images

Pentru crearea unui container pe baza imaginii, o să folosim următoarea comandă:

docker run -d --restart always -p 3000:3000 nextjs-docker

Prin rularea acesti comenzi, ne asigurăm de faptul că de fiecare dată când instanța noastră este repornită, containerul o să pornească și el.

La sfârșit, putem să accesăm adresa IP (Elastic IP-ul) și să ne asigurăm de faptul că totul funcționează.

4.8. Actualizarea codului pe instanță

Să presupunem că am dorit să mai actualizăm sau să urcăm ceva nou pe GitHub, dar codul pe instanță nu s-a actualizat.

În acest caz, ar trebui să intervenim ori cu un pipeline care să facă totul singur și automat, fie să actualizăm noi codul manual, conectându-ne la instanță SSH.

O să mergem pe a doua variantă, și o să actualizăm codul manual.

Să presupun că la formularul de creare a unui nou record, vrem să adăugăm și un titlu.

Noua variantă a fișierului RecordForm.jsx:

// /components/RecordForm.jsx

import React, { useState } from "react";
import { useRouter } from "next/router";

const RecordForm = (props) => {
  const { data, onSubmit } = props;
  const router = useRouter();
  const [entry, setEntry] = useState(data);

  const updateEntry = (type, value) => {
    setEntry({ ...entry, [type]: value });
  };

  const handleCancel = () => {
    router.push("/");
  }

  return (
    <div className="flex justify-center p-4">
      <div className="border p-4 rounded-md shadow-sm flex flex-col gap-4 w-full max-w-80">
        <h1 className="font-bold text-center text-lg">Create new Record</h1>
        <div>
          <label
            htmlFor="title"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
          >
            Title
          </label>
          <input
            type="text"
            id="title"
            value={entry.title}
            onChange={(e) => updateEntry("title", e.target.value)}
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
            placeholder="Title"
            required
          />
        </div>
        <div>
          <label
            htmlFor="description"
            className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
          >
            Description
          </label>
          <textarea
            id="description"
            rows="4"
            value={entry.description}
            onChange={(e) => updateEntry("description", e.target.value)}
            className="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
            placeholder="Write your thoughts here..."
          ></textarea>
        </div>
        <div className="w-full flex justify-center gap-4">
            <button
            type="button"
            onClick={handleCancel}
            className="focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
          >
            Cancel
          </button>
          <button
            type="button"
            onClick={() => onSubmit(entry)}
            className="focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"
          >
            {entry._id ? "Update" : "Create"}
          </button>
        </div>
      </div>
    </div>
  );
};

export default RecordForm;

Următorul pas, este reprezentat de actualizarea codului pe GitHub. (git add ., git commit, git push)

După ce am actualizat codul, ne mutăm iar în cadrul terminalului prin care suntem conectați la instanță, ne asigurăm că suntem încă în folderul unde s-a clonat proiectul, și actualizăm și acolo codul cu următoarea comandă:

git pull

Ca să putem să actualizăm codul, trebuie să ne asigurăm că ștergem imaginea și containerul create la pasul anterior, și să le creăm din nou.

Prima dată, trebuie să oprim containerul de docker care rulează. Pentru a verifica ce containere avem, o să folosim comanda:

docker ps

Copiem id-ul container-ului de docker, și rulăm următoarea comandă:

docker stop a231dedf4ad8

Continuăm cu ștergerea container-ului:

docker rm a231dedf4ad8

Ulterior, verificăm lista de imagini:

docker image ls

Mai departe, luăm id-ul și folosim următoarea comandă pentru a o șterge:

docker rmi 3b7806bb37b1

Acum, suntem gata să dăm iar build la aplicație și să îi spunem docker-ului să repornească singur de fiecare dată când instanța repornește și ea.

Accesăm iar adresa IP, și o să putem să vedem modificările:

5. Oprirea instanței

Ne deplasăm la secțiunea dedicată instanțelor EC2, și o alegem pe aceea pe care ne dorim să o oprim, și o accesăm.

După ce am selectat-o, mutăm cursorul la secțiunea Instance state -> Stop instance.

Aveți foarte mare grijă să nu apăsați pe Terminate Instance, deoarece nu o să mai puteți să reporniți insanța niciodată.

Este recomandat să folosim acea acțiune, doar atunci când dorim să renunțăm la respectiva instanță.

6. Pornirea instanței

Aflându-ne tot pe pagina cu instanța pe care dorim să o pornim, mergem cu cursorul pe Instance state -> Start instance.

Dacă am urmat pașii de la partea de Docker, containerul care conține build-ul codului ar trebui să repornească automat și să își păstreze IP-ul, datorită Elastic IP-ului.

Instrucțiunile detaliate pentru instalarea Docker pe o instanță EC2 cu Ubuntu 22.04, le puteți găsi și aici:

3️
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-22-04
https://signin.aws.amazon.com/