Docker – Wprowadzenie do konteneryzacji

W dzisiejszym świecie tworzenia aplikacji coraz częściej spotykamy się z pojęciem konteneryzacji. Dzięki niej możemy łatwo pakować aplikacje wraz z całym środowiskiem uruchomieniowym, co upraszcza wdrażanie i eliminuje problem „u mnie działa”. Najpopularniejszym narzędziem do konteneryzacji jest Docker.

W tym wpisie pokażę Ci, jak można  w obrazie kontenerowym zbudować aplikację i uruchomić ją lokalnie.

I. Tworzenie aplikacji w kontenerze

1. Stworzenie aplikacji

Na początek potrzebujemy aplikacji. Będzie to aplikacja napisana w Node.js. i jest to przykładowa lista rzeczy do zrobienia:

Przykład zaciągnięty z: https://www.docker.com/101-tutorial/

2. Budowanie obrazu aplikacji

Aby uruchomić aplikację w kontenerze, musimy stworzyć Dockerfile – plik, który opisuje, jak zbudować obraz naszej aplikacji.

a) Tworzenie pliku Dockerfile

Utwórz plik Dockerfile w katalogu głównym projektu i dodaj do niego następującą treść:

FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

Opis poszczególnych poleceń:

  • FROM node:18-alpine – bazujemy na oficjalnym obrazie Node.js.

  • WORKDIR /app – ustawiamy katalog roboczy.

  • COPY . . – kopiujemy wszystkie pliki do kontenera.

  • RUN yarn install --production – instalujemy zależności.

  • CMD ["node", "src/index.js"] – komenda uruchamiająca aplikację.

b) Budowanie obrazu

Otwórz terminal w katalogu z projektem i uruchom:

docker build -t getting-started .

 

To polecenie zbuduje obraz kontenerowy i nazwie go getting-started.

3. Start kontenera aplikacji

Gdy obraz jest już gotowy, możemy uruchomić kontener:

docker run -dp 3000:3000 getting-started

 

  • -d – uruchamia kontener w tle (detached mode),

  • -p 3000:3000 – mapuje port lokalny 3000 na port 3000 w kontenerze.

Teraz wystarczy wejść w przeglądarkę i otworzyć:

http://localhost:3000

Powinieneś zobaczyć pustą listę rzeczy do zrobienia.  🎉

 

Zbudowanie aplikacji bazującej na React i Firebase: CRUD

Kolejne kroki:

  • Instalacja środowiska programistycznego np. ‘Visual Studio Code‘.
  • Instalacja Node.js.
  • Weryfikacja instalacji:

node -v

npm -v

  • Tworzenie projektu React JS:

npx create-react-app todoapp

cd todoapp

code .

npm start

  • Tworzenie projektu Firebase.
  • Tworzenie bazy danych dla aplikacji:
    a)klikamy ‘Firestore database
    b)następnie: ‘Start in test mode
    c) nadanie nazwy dla kolekcji
    d) dodanie jakichś przykładowych danych
  • Integracja Firebase z projektem React

npm install firebase

  • Stworzenie pliku konfiguracyjnego ‘firebase.js‘ w katalogu źródłowym. Tutaj dodajemy konfigurację z Firebase do połączenia:
    a) klikamy w ikonkę Web ”
    b) nadanie nazwy dla naszej aplikacji
    c) rejestracja aplikacji
    d) skopiowanie ‘firabaseConfig
//zawartość pliku 'firebase.js'
import { initializeApp } from "firebase/app"

const firebaseConfig = { //tutaj trzeba uzupełnić własną konfiguracją

  apiKey: "",

  authDomain: "",

  projectId: "",

  storageBucket: "",

  messagingSenderId: "",

  appId: ""

};

export const app = initializeApp(firebaseConfig);
//App.js
import './App.css';
import { Component } from 'react';
import { collection, deleteDoc, getDocs, getFirestore, addDoc, doc, setDoc } from 'firebase/firestore/lite';
import { app } from './firebase';

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      notes: []
    }
  }

  async refreshNotes() {
    var notesList = [];
    const db = getFirestore(app);
    const notesCol = collection(db, 'notes');
    const notesSnapshot = await getDocs(notesCol);

    notesSnapshot.forEach(doc => {
      let note = doc.data();
      note.id = doc.id;
      notesList.push(note);
    });
    this.setState({ notes: notesList });
  }

  componentDidMount() {
    this.refreshNotes();
  }

  async addClick() {
    var newNotes = document.getElementById("newNotes").value;
    var newNotesObject = { description: newNotes };
    const db = getFirestore(app);
    const notesCol = collection(db, 'notes');
    await addDoc(notesCol, newNotesObject);
    this.refreshNotes();
  }

  async deleteClick(id) {
    const db = getFirestore(app);
    const notesRef = doc(db, 'notes/' + id);

    await deleteDoc(notesRef);
    this.refreshNotes();
  }

  async updateClick(id) {
    const updatedDescription = prompt("Enter the updated description:");
    if (!updatedDescription) return; // If user cancels the prompt

    const db = getFirestore(app);
    const notesRef = doc(db, 'notes', id);

    await setDoc(notesRef, { description: updatedDescription }, { merge: true });
    this.refreshNotes();
  }

  render() {
    const { notes } = this.state;
    return (
      <div className="App">
        <h2>Todoapp</h2>
        <input id="newNotes" /> 
        <button onClick={() => this.addClick()}>Add Notes</button>
        {notes.map(note =>
          <p>
            <b>* {note.description}</b>  
            <button onClick={() => this.deleteClick(note.id)}>Delete Notes</button>
            <button onClick={() => this.updateClick(note.id)}>Update Notes</button>
          </p>
        )}
      </div>
    );
  }
}

export default App;

Opcjonalnie/dodatkowo możemy:

  1. Zainstalować wtyczkę Visual Studio Extension: ‘Prettier-Code formatter‘ do sformatowania kodu żeby bardziej przejrzyście wyglądał
    skrót: ‘Ctrl + Shift + I’ do użycia po włączeniu wtyczki
  2. Instalacja rozszerzenia ‘Print‘, jeżeli chcemy wydrukować kod źródłowy.