Il 0% ha trovato utile questo documento (0 voti)
4 visualizzazioni62 pagine

Dev Ops

Il documento fornisce una panoramica su Cloud Computing e Spring Boot, evidenziando le origini tecnologiche, i benefici, i modelli di distribuzione e di servizio del cloud. Inoltre, descrive i concetti chiave di Spring Boot, come l'Inversion of Control, la Dependency Injection e la gestione della persistenza dei dati tramite JPA e ORM. Infine, viene trattato lo sviluppo di applicazioni web con Spring Web MVC e le annotazioni utilizzate per la configurazione e la gestione delle entità.

Caricato da

vinaf94343
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
4 visualizzazioni62 pagine

Dev Ops

Il documento fornisce una panoramica su Cloud Computing e Spring Boot, evidenziando le origini tecnologiche, i benefici, i modelli di distribuzione e di servizio del cloud. Inoltre, descrive i concetti chiave di Spring Boot, come l'Inversion of Control, la Dependency Injection e la gestione della persistenza dei dati tramite JPA e ORM. Infine, viene trattato lo sviluppo di applicazioni web con Spring Web MVC e le annotazioni utilizzate per la configurazione e la gestione delle entità.

Caricato da

vinaf94343
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

devOps.

md 2026-05-07

Riassunto DevOps e Cloud Computing


1. Cloud Computing
Il Cloud Computing è la pratica di utilizzare una rete di server remoti ospitati su Internet per archiviare,
gestire ed elaborare dati, anziché un server locale o un computer personale. Esso consente alle aziende di
consumare risorse di calcolo come un servizio di pubblica utilità (utility), simile all'elettricità, eliminando la
necessità di costruire e mantenere infrastrutture interne.

Origini Tecnologiche

Il Cloud Computing trae le sue origini da diverse tecnologie abilitanti:

Virtualizzazione: La tecnologia principale che permette di astrarre le risorse hardware.


Service-Oriented Architecture (SOA): Il cloud adotta i concetti di SOA per fornire funzionalità tramite
servizi.
Grid Computing: Utilizzato per il calcolo parallelo intensivo di dati.

Benefici Principali

Self-service provisioning: Gli utenti possono attivare risorse di calcolo su richiesta per quasi ogni tipo
di carico di lavoro.
Elasticità: Capacità di scalare rapidamente (scale up) quando le esigenze aumentano e ridurre (scale
down) quando diminuiscono.
Pay-per-use: Le risorse sono misurate a livello granulare, permettendo di pagare solo per ciò che viene
effettivamente utilizzato (economia di scala).

Modelli di Distribuzione

On-Premises: Software installato e prudenziato direttamente sui computer all'interno dell'edificio


dell'organizzazione, invece di una struttura remota.
Pubblico: I servizi sono venduti on-demand (tipicamente al minuto o all'ora) da provider esterni (es.
AWS, Azure, Google Cloud). I clienti pagano solo per cicli di CPU, storage o larghezza di banda
consumati.
Privato: Servizi erogati da un data center a utenti interni. Offre versatilità e convenienza preservando
gestione, controllo e sicurezza.
Ibrido: Permette alle aziende di eseguire carichi di lavoro mission-critical o sensibili sul cloud privato,
utilizzando il cloud pubblico per i carichi che richiedono scalabilità on-demand.
Multi-Cloud: Utilizzo di più servizi cloud di diversi provider in un'unica architettura eterogenea per
eliminare la dipendenza da un singolo fornitore.

1 / 62
[Link] 2026-05-07

Modelli di Servizio (XaaS)

IaaS (Infrastructure as a Service): Fornisce risorse di calcolo come server, rete e archiviazione (es.
AWS, Azure). Permette di scalare l'infrastruttura su richiesta senza investimenti in hardware fisico.
PaaS (Platform as a Service): Fornisce un ambiente completo per lo sviluppo e la distribuzione di
applicazioni web, gestendo il middleware e l'hosting (es. Google App Engine). Riduce la complessità
fornendo "middleware as a service".
SaaS (Software as a Service): Applicazioni basate su cloud accessibili via web, gestite da terzi (es.
Microsoft Office 365). I dati sono sicuri nel cloud anche in caso di guasto del computer locale.

Applicazioni Cloud-Native

Le applicazioni cloud-native sono progettate per girare su macchine virtuali o container. Si basano su:

Infrastruttura elastica e provisioning tramite API.


Microservizi: Applicazioni composte da servizi a grana fine comunicanti tramite API.
Resilienza: Capacità di rilevare e gestire i guasti automaticamente.

2 / 62
[Link] 2026-05-07

2. Spring Boot
Spring Boot è una soluzione "opinionated" basata sul framework Spring che facilita la creazione di
applicazioni stand-alone di grado produttivo grazie al principio della convention-over-configuration.

Core Concepts

Inversion of Control (IoC): Principio per cui il controllo del flusso del programma viene trasferito al
framework.
Dependency Injection (DI): Meccanismo per realizzare l'IoC, permettendo al container di Spring di
iniettare le dipendenze necessarie tramite costruttori, setter o campi.
Spring IoC Container: Rappresentato dall'interfaccia ApplicationContext, è responsabile
dell'istanziazione, configurazione e assemblaggio dei "beans", gestendone l'intero ciclo di vita.

Annotazioni e Gestione dei Bean

Il container utilizza i metadati delle annotazioni per assemblare i componenti:

@Configuration: Indica che una classe è una sorgente di definizioni di bean. All'interno di queste classi
si definiscono i metodi per creare i componenti.
@Bean: Utilizzata sui metodi di una classe @Configuration per restituire un oggetto che Spring deve
registrare come bean nel contesto dell'applicazione. Per impostazione predefinita, i bean sono oggetti

singleton.
@Component: Utilizzata per l'auto-rilevamento (classpath scanning) e l'auto-configurazione dei bean.
Versioni specializzate sono @Service (per la logica di business) e @Repository (per l'accesso ai dati).
@Autowired: Marca un costruttore, un campo o un metodo setter affinché Spring possa iniettare
automaticamente la dipendenza richiesta.

3 / 62
[Link] 2026-05-07

Persistenza dei Dati con JPA e ORM

L'integrazione con i database è gestita tramite standard moderni che risolvono il disallineamento tra oggetti e
tabelle relazionali:

ORM (Object-Relational Mapping): Permette di gestire il disallineamento tra il modello a oggetti


(Java) e quello relazionale (Database).
JPA (Java Persistence API): Specificazione standard per l'ORM introdotta con Java 5. Richiede un
provider per l'implementazione (es. Hibernate o EclipseLink). Se lo standard JPA è rispettato, è
possibile cambiare il provider senza modificare il codice.
Spring Data JPA: Sotto-progetto di Spring che semplifica l'accesso ai dati, supportando sia database
relazionali (JDBC, JPA) che NoSQL (Redis, MongoDB). Automatizza la creazione dei Repository tramite
interfacce (es. JpaRepository).

Sviluppo Web con Spring Web MVC

4 / 62
[Link] 2026-05-07

Spring Web
MVC è il framework web originale di Spring, basato sulla Servlet API e progettato secondo il pattern Model-
View-Controller:

DispatcherServlet: Il cuore del framework che smista le richieste agli handler corretti.
@RestController: Contrassegna una classe come controller web, pronta per gestire richieste HTTP e
restituire tipicamente JSON.
@RequestMapping: Mapper per le richieste web (es. /users). Esistono varianti specifiche come
@GetMapping, @PostMapping, @PutMapping e @DeleteMapping.
Gestione Parametri:
@PathVariable: Per estrarre valori dal percorso dell'URL.
@RequestBody: Per mappare il corpo della richiesta (JSON) su un oggetto Java.
@RequestParam: Per gestire i parametri di query (es. ?name=John).
ResponseEntity: Utilizzato nei metodi del controller per avere pieno controllo sulla risposta HTTP
(status code, headers, body).

Spring Boot Deepening

Auto-Configuration

Spring Boot Auto-Configuration è il meccanismo centrale di Spring Boot che applica il principio
convention-over-configuration:

@SpringBootApplication: Annotazione che combina @Configuration, @EnableAutoConfiguration


e @ComponentScan in una singola annotazione conveniente.
@EnableAutoConfiguration: Istruisce Spring Boot di indovinare automaticamente come configurare
Spring in base alle dipendenze JAR presenti nel classpath.
5 / 62
[Link] 2026-05-07

Auto-Configuration Classes: Spring Boot fornisce automaticamente classi di configurazione per le


dipendenze comuni (es. DataSourceAutoConfiguration per i database, WebMvcAutoConfiguration
per il web).
Conditional Beans: Le auto-configuration usano annotazioni come @ConditionalOnClass,
@ConditionalOnMissingBean, @ConditionalOnProperty per decidere se istanziare certi bean:

@Configuration
@ConditionalOnClass([Link])
public class DataSourceAutoConfiguration { ... }

[Link]/yml: File dove configurare il comportamento dell'applicazione. Spring Boot


carica automaticamente [Link] (o [Link]) da classpath.
Esclusione di Auto-Configuration: Tramite l'attributo exclude di @SpringBootApplication:

@SpringBootApplication(exclude = [Link])

Spring Boot Starters

Gli Starters sono dipendenze Maven/Gradle che semplificano il setup aggiungendo automaticamente tutte le
dipendenze transitive necessarie:

spring-boot-starter-web: Include Spring Web MVC, Tomcat embedded, Jackson per JSON.
spring-boot-starter-data-jpa: Include JPA, Hibernate, Spring Data.
spring-boot-starter-data-rest: Espone repository JPA come REST API automaticamente.
spring-boot-starter-security: Integra Spring Security per autenticazione e autorizzazione.
spring-boot-starter-actuator: Aggiunge endpoint di monitoraggio e health check.
spring-boot-starter-test: Include JUnit, Mockito, AssertJ per il testing.
Vantaggi: Evitano di specificare manualmente versioni compatibili; Spring Boot garantisce che i starter
funzionino insieme.

Configurazione dell'Applicazione

[Link]: Formato chiave=valore (es. [Link]=8080,


[Link]=jdbc:...).
[Link]: Formato YAML, più leggibile per configurazioni complesse:

server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret

6 / 62
[Link] 2026-05-07

jpa:
hibernate:
ddl-auto: update

Environment-Specific Profiles: È possibile creare file come [Link],


[Link] e attivarli tramite [Link]=dev.
Injection di Proprietà: Tramite @Value o @ConfigurationProperties:

@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig {
private String name;
private String version;
// getters/setters
}

JPA e Data Persistence

JPA (Java Persistence API) è uno standard per l'ORM (Object-Relational Mapping) che astrae i dettagli della
persistenza. Spring Data JPA semplifica ulteriormente il lavoro fornendo repository generici.

Entity Definition: Un'entità è una classe Java che rappresenta una tabella del database:

@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@Column(name = "user_name", unique = true, nullable = false)


private String name;

@Column(nullable = false)
private String email;

@CreationTimestamp
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;

@UpdateTimestamp
@Column(name = "updated_at")
private LocalDateTime updatedAt;

// getters/setters
}

7 / 62
[Link] 2026-05-07

Annotazioni Entity principali:

@Entity: Contrassegna la classe come entità JPA.


@Table: Specifica il nome della tabella (di default usa il nome della classe in minuscolo).
@Id: Identifica il campo come chiave primaria.
@GeneratedValue: Strategia di generazione dell'ID:
IDENTITY: Auto-increment dal database.
SEQUENCE: Usa sequenze del database.
TABLE: Usa una tabella speciale per tracciare gli ID.
UUID: Genera UUID automaticamente.
@Column: Configurazione della colonna (nome, vincoli, lunghezza).
@Temporal: Specifica il tipo temporale (DATE, TIME, TIMESTAMP).
@CreationTimestamp / @UpdateTimestamp: Auditing automatico (Hibernate-specific).
@Transient: Esclude un campo dalla persistenza.
@Enumerated: Serializza enum come ORDINAL o STRING.

Repository Pattern: Spring Data JPA fornisce interfacce generiche per il CRUD:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// CRUD automatico: save(), findById(), findAll(), delete(), deleteById()...

// Custom query methods (derivate dal nome)


User findByEmail(String email);
List<User> findByNameContainingIgnoreCase(String name);
List<User> findByEmailAndNameOrderByCreatedAtDesc(String email, String name);

// Custom @Query (JPQL)


@Query("SELECT u FROM User u WHERE [Link] = ?1")
User findUserByEmail(String email);

// Native SQL
@Query(value = "SELECT * FROM users WHERE name LIKE %?1%", nativeQuery = true)
List<User> searchByNameNative(String name);

// Pagination
Page<User> findAll(Pageable pageable);

// Deleting
@Modifying
@Transactional
void deleteByEmail(String email);
}

Query Method Naming Convention: Spring Data JPA genera query automaticamente dal nome del metodo:

findBy<PropertyName>: Trova per proprietà.


findBy<PropertyName>Is: Equivale a =.
findBy<PropertyName>Like: Usa LIKE.

8 / 62
[Link] 2026-05-07

findBy<PropertyName>In(Collection): IN clause.
findBy<PropertyName>GreaterThan: >, LessThan: <, etc.
findBy<PropertyName>Between: BETWEEN.
findBy<PropertyName>StartingWith / EndingWith: Per stringhe.
findBy<PropertyName1>And<PropertyName2>: AND logico.
findByNameIgnoreCase: Case-insensitive.
OrderBy<PropertyName>Desc / Asc: Ordinamento.

Relazioni tra Entità:

One-to-One:

@Entity
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@OneToOne(cascade = [Link], fetch = [Link])


@JoinColumn(name = "profile_id", unique = true)
private Profile profile;
}

@Entity
public class Profile {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@OneToOne(mappedBy = "profile")
private User user; // Lato inverse, non ha @JoinColumn
}

One-to-Many / Many-to-One:

@Entity
public class Author {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@OneToMany(mappedBy = "author", cascade = [Link], fetch =


[Link])
private Set<Book> books = new HashSet<>();
}

@Entity
public class Book {
@Id
@GeneratedValue(strategy = [Link])
9 / 62
[Link] 2026-05-07

private Long id;

@ManyToOne(fetch = [Link])
@JoinColumn(name = "author_id", nullable = false)
private Author author;
}

Many-to-Many:

@Entity
public class Student {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@ManyToMany(cascade = [Link], fetch = [Link])


@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}

@Entity
public class Course {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
}

Fetch Strategy (Lazy vs Eager):

[Link]: Carica i dati associati solo quando acceduti (di default per *-to-many). Più efficiente
ma rischia LazyInitializationException.
[Link]: Carica i dati associati immediatamente (di default per *-to-one). Semplice ma
genera query JOIN automatiche.

Cascade Types:

[Link]: Persiste l'entità genitore anche gli aggregati.


[Link]: Elimina anche le entità figlie.
[Link]: Merge ricorsivo.
[Link]: Refresh ricorsivo.
[Link]: Applica tutti i tipi.

10 / 62
[Link] 2026-05-07

N+1 Problem e Soluzioni: Il problema N+1 si verifica quando per ogni entità principale si esegue una query
separata per caricarne le relazioni:

// PROBLEMA: N+1 query


List<Author> authors = [Link](); // 1 query
for (Author author : authors) {
[Link]([Link]()); // N query aggiuntive
}

Soluzioni:

1. Eager Loading:

@OneToMany(fetch = [Link])
private Set<Book> books;

2. @Query con JOIN FETCH:

@Query("SELECT a FROM Author a JOIN FETCH [Link]")


List<Author> findAllWithBooks();

3. EntityGraph:

@EntityGraph(attributePaths = {"books"})
@Query("SELECT a FROM Author a")
List<Author> findAllWithBooksGraph();

4. @Transactional con lazy loading controllato:

@Transactional
public List<AuthorDTO> getAuthorsWithBooks() {
List<Author> authors = [Link]();
[Link](a -> [Link]().size()); // Forza il caricamento
return mapToDTO(authors);
}

Auditing con Entities: Spring Data JPA fornisce auditing automatico tramite @CreationTimestamp e
@UpdateTimestamp (Hibernate) oppure:

@Entity
@EntityListeners([Link])
public class User {
11 / 62
[Link] 2026-05-07

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;

@CreatedBy
private String createdBy;

@LastModifiedBy
private String updatedBy;
}

Validazione con Entities:

@Entity
public class User {
@NotNull
@NotEmpty
private String name;

@Email
@NotNull
private String email;

@Min(18)
@Max(120)
private Integer age;
}

Paginazione e Sorting:

// Controller
@GetMapping("/users")
public Page<User> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id") String sortBy) {

Pageable pageable = [Link](page, size, [Link](sortBy).ascending());


return [Link](pageable);
}

// Response
{
"content": [...],
"pageable": { "pageNumber": 0, "pageSize": 10 },
"totalElements": 50,
"totalPages": 5,

12 / 62
[Link] 2026-05-07

"last": false,
"first": true,
"numberOfElements": 10,
"empty": false
}

Specification per Query Dinamiche:

public interface UserRepository extends JpaRepository<User, Long>,


JpaSpecificationExecutor<User> {
}

@Service
public class UserService {
@Autowired
private UserRepository repository;

public List<User> search(String name, String email) {


Specification<User> spec = [Link](null);
if (name != null) {
spec = [Link]((root, query, cb) -> [Link]([Link]("name"), "%" +
name + "%"));
}
if (email != null) {
spec = [Link]((root, query, cb) -> [Link]([Link]("email"),
email));
}
return [Link](spec);
}
}

DTOs e Mapping: Per evitare serializzare entità complete, si usano DTOs:

@Data
public class UserDTO {
private Long id;
private String name;
private String email;

public static UserDTO from(User user) {


UserDTO dto = new UserDTO();
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
return dto;
}
}

@RestController

13 / 62
[Link] 2026-05-07

public class UserController {


@GetMapping("/{id}")
public UserDTO getUser(@PathVariable Long id) {
return [Link](id)
.map(UserDTO::from)
.orElseThrow();
}
}

Exception Handling e Validation

@ControllerAdvice: Classe globale per gestire eccezioni in tutta l'applicazione:

@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse>
handleNotFound(EntityNotFoundException e) {
return [Link](HttpStatus.NOT_FOUND).body(new
ErrorResponse([Link]()));
}
}

@ExceptionHandler: Metodo che intercetta un tipo specifico di eccezione.


Bean Validation (JSR-380/Jakarta Validation): Annotazioni per validare i dati:
@NotNull, @NotEmpty, @Size, @Email, @Pattern (regex), @Positive, ecc.

@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody User user) {
return [Link](user);
}

@Valid: Istruisce Spring a validare il payload prima di passarlo al metodo; gli errori vengono raccolti in
BindingResult.

Transaction Management

Le transazioni garantiscono che le operazioni sul database rispettino le proprietà ACID (Atomicity,
Consistency, Isolation, Durability):

@Transactional: Annotazione che demarca i confini transazionali. Applicata a livello di metodo o


classe:

@Service
public class UserService {
@Transactional
14 / 62
[Link] 2026-05-07

public void updateUser(Long id, String name) {


User user = [Link](id).orElseThrow();
[Link](name);
[Link](user); // flush automatico al commit
}
}

Transaction Propagation: Definisce come una transazione si comporta quando un metodo


transazionale chiama un altro metodo transazionale:
REQUIRED (default): Usa la transazione esistente, ne crea una nuova se non esiste.
REQUIRES_NEW: Crea sempre una nuova transazione, sospendendo quella attuale.
NESTED: Crea un savepoint dentro la transazione esistente (se supportato dal DB).
MANDATORY: Richiede che una transazione sia già attiva; lancia eccezione altrimenti.
SUPPORTS: Usa la transazione se esiste, altrimenti prosegue senza.
NOT_SUPPORTED: Esegue il metodo senza transazione, sospendendo quella attuale.
NEVER: Lancia eccezione se una transazione è attiva.

Isolation Levels (Livelli di Isolamento ANSI SQL)

I livelli di isolamento controllano come le transazioni concorrenti interagiscono, bilanciando consistenza e


performance:

Non-
Dirty Phantom
Livello Repeatable Descrizione
Read Read
Read

Consente lettura di dati non ancora


READ_UNCOMMITTED ✓ (Sì) ✓ (Sì) ✓ (Sì) committati. Livello più debole; usato
raramente.

Legge solo dati committati. Default



READ_COMMITTED ✓ (Sì) ✓ (Sì) su molti DB (es. SQL Server, Oracle).
(No)
Protegge da dirty read.

Stessa riga letta due volte ritorna


✗ stesso valore. Default su MySQL.
REPEATABLE_READ ✗ (No) ✓ (Sì)
(No) Una transazione vede uno snapshot
consistente.

Livello più forte; tratta transazioni



SERIALIZABLE ✗ (No) ✗ (No) come seriali. Può ridurre
(No)
drasticamente la concorrenza.

Problemi di Concorrenza:

Dirty Read: Una transazione legge dati modificati da un'altra transazione non ancora committata.
Non-Repeatable Read: Una riga letta due volte in una transazione ritorna valori diversi (altra
transazione l'ha modificata e committata).
Phantom Read: Una query eseguita due volte ritorna righe diverse (un'altra transazione ha
inserito/eliminato righe).
15 / 62
[Link] 2026-05-07

Configurazione in Spring Boot:

@Service
public class OrderService {
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation =
[Link])
public void processOrder(Order order) {
// operazioni critiche
}
}

Readonly Transactions: Per operazioni di sola lettura, impostare readOnly = true per ottimizzazioni:

@Transactional(readOnly = true)
public List<User> getAllUsers() {
return [Link]();
}

Rollback e Gestione Eccezioni:

Per default, Spring esegue il rollback solo su eccezioni non-checked (RuntimeException e sottoclassi).
Per eccezioni checked (es. IOException), usare rollbackFor:

@Transactional(rollbackFor = [Link])
public void uploadFile(MultipartFile file) throws IOException {
// se IOException viene lanciata, la transazione eseguirà rollback
}

noRollbackFor: Eccezioni che NON causano rollback anche se lanciate:

@Transactional(noRollbackFor = [Link])
public void updateData(Data data) {
// ValidationException non causa rollback
}

Timeout Transazionale:

@Transactional(timeout = 30) // timeout in secondi


public void longRunningOperation() {
// se impiega più di 30 secondi, Spring la rollback automaticamente
}

Transaction Manager in Spring:


16 / 62
[Link] 2026-05-07

Spring Boot auto-configura il PlatformTransactionManager appropriato in base alle dipendenze (es.


JpaTransactionManager per JPA, DataSourceTransactionManager per JDBC puro).
Configurazione manuale rara; preferire @Transactional su metodi di servizio.

Savepoints (per DB che li supportano):

@Transactional(propagation = [Link])
public void methodWithSavepoint() {
// Se questa transazione fallisce, il DB esegue rollback solo fino al
savepoint,
// la transazione padre continua
}

Spring Boot Testing

Spring Boot fornisce @SpringBootTest per test di integrazione che caricano il contesto completo:

@SpringBootTest
class UserControllerTest {
@MockBean
private UserService userService;

@Autowired
private TestRestTemplate restTemplate;

@Test
void testGetUser() {
[Link]([Link](1L)).thenReturn(new User(1L, "John"));
ResponseEntity<User> response = [Link]("/users/1",
[Link]);
assertEquals([Link], [Link]());
}
}

@WebMvcTest: Test slice che carica solo il layer web (controller), senza database.
@DataJpaTest: Test slice per il layer di persistenza (repository e JPA).
TestRestTemplate: Client HTTP per testare REST API in test di integrazione.
MockMvc: Alterna al TestRestTemplate, utile per test più granulari su controller.

Spring Boot Actuator

Actuator aggiunge endpoint di monitoraggio e health check:

GET /actuator/health: Stato di salute dell'applicazione (UP, DOWN). Include dettagli su database,
disco, ecc.
GET /actuator/metrics: Metriche raccolte (numero di richieste, latenza, memory usage).
GET /actuator/env: Proprietà di environment e configurazione.

17 / 62
[Link] 2026-05-07

GET /actuator/beans: Elenco di tutti i bean caricati nel contesto.


GET /actuator/info: Informazioni custom sull'applicazione (versione, descrizione, ecc. definite in
[Link]).
Enabling Actuator: Aggiungere la dipendenza spring-boot-starter-actuator a Maven/Gradle.
Custom Endpoints: È possibile creare endpoint personalizzati con @Endpoint o
@RestControllerEndpoint:

@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public String getCustomInfo() {
return "Custom data";
}
}

Logging in Spring Boot

Spring Boot usa Logback di default (implementazione SLF4J):

Configurazione semplice: tramite [Link]:

[Link]=INFO
[Link]=DEBUG
[Link]=logs/[Link]

Configurazione avanzata: tramite file [Link] nella root di classpath per controllo
granulare su appenders, pattern, rolling policies.
Log nei bean: tramite SLF4J:

@Component
public class MyService {
private static final Logger logger =
[Link]([Link]);

public void doSomething() {


[Link]("Operazione completata");
}
}

Embedded Servers e Deployment

Embedded Tomcat: Spring Boot Web MVC include un server Tomcat embedded (port di default 8080).
Embedded Jetty/Undertow: Alternative a Tomcat escludendo spring-boot-starter-tomcat e
aggiungendo l'starter Jetty/Undertow.

18 / 62
[Link] 2026-05-07

Fat JAR (Uber JAR): Generato con ./mvnw clean package. Contiene tutte le dipendenze e il server
embedded; può essere eseguito direttamente con java -jar [Link].
WAR Deploy: Se si vuole deployare su app server esterno, si può generare un WAR tramite estensione
di SpringBootServletInitializer.

HATEOAS (Hypermedia As The Engine Of Application State)

HATEOAS è un vincolo del modello REST che dice che i client devono interagire con l'applicazione tramite
ipermedia (links) forniti dal server, anziché costruire URL hardcoded. Questo rende l'API più flessibile e auto-
descrittiva.

Concetto Chiave:

Invece di dover conoscere tutti gli endpoint in anticipo, il client riceve dal server i link verso le azioni
disponibili.

I link guidano il client attraverso l'applicazione come ipertesti in HTML.

Esempio senza HATEOAS:

{
"id": 1,
"name": "John Doe",
"email": "john@[Link]"
}

Il client deve sapere che l'URL è /users/1 e che per aggiornare deve fare POST a /users/1/update.

Esempio con HATEOAS:

{
"id": 1,
"name": "John Doe",
"email": "john@[Link]",
"_links": {
"self": { "href": "/users/1" },
"all_users": { "href": "/users" },
"update": { "href": "/users/1", "method": "PUT" },
"delete": { "href": "/users/1", "method": "DELETE" }
}
}

Il client scopre le azioni disponibili dai link forniti dal server.

Spring HATEOAS: Spring HATEOAS è una libreria che semplifica l'implementazione di HATEOAS tramite
spring-boot-starter-hateoas:

19 / 62
[Link] 2026-05-07

// Dipendenza Maven
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

Implementazione pratica:

@RestController
@RequestMapping("/users")
public class UserController {

@GetMapping("/{id}")
public EntityModel<User> getUser(@PathVariable Long id) {
User user = [Link](id).orElseThrow();

// Crea la rappresentazione hypermedia


return [Link](user,
linkTo(methodOn([Link]).getUser(id)).withSelfRel(),

linkTo(methodOn([Link]).getAllUsers()).withRel("all_users"),
linkTo(methodOn([Link]).updateUser(id,
null)).withRel("update"),

linkTo(methodOn([Link]).deleteUser(id)).withRel("delete")
);
}

@GetMapping
public CollectionModel<EntityModel<User>> getAllUsers() {
List<User> users = [Link]();
List<EntityModel<User>> userModels = [Link]()
.map(u -> [Link](u,

linkTo(methodOn([Link]).getUser([Link]())).withSelfRel()
))
.collect([Link]());

return [Link](userModels,
linkTo(methodOn([Link]).getAllUsers()).withSelfRel()
);
}
}

Componenti principali di Spring HATEOAS:

Link: Rappresenta un singolo link hypermedia con href (URL) e rel (relazione semantica):

20 / 62
[Link] 2026-05-07

Link selfLink = [Link]("/users/1", "self");

EntityModel: Wrapper attorno a una singola risorsa che aggiunge link:

EntityModel<User> userModel = [Link](user, links);

CollectionModel: Wrapper per collezioni di risorse con link per la collection:

CollectionModel<EntityModel<User>> users = [Link](userModels,


selfLink);

linkTo() e methodOn(): DSL per generare link type-safe basati sui metodi del controller:

linkTo(methodOn([Link]).getUser(1L)).withSelfRel()
// Genera: href="/users/1", rel="self"

Relazioni semantiche comuni:

self: Link alla risorsa corrente.


all: Link alla collezione completa.
create: Link per creare una nuova risorsa.
update: Link per aggiornare la risorsa.
delete: Link per eliminare la risorsa.
first, last, next, prev: Relazioni di paginazione.
custom-rel: Relazioni personalizzate.

HATEOAS con Paginazione:

@GetMapping
public PagedModel<EntityModel<User>> getAllUsers(
@PageableDefault(size = 10) Pageable pageable) {

Page<User> page = [Link](pageable);

return [Link](
[Link](u -> [Link](u,

linkTo(methodOn([Link]).getUser([Link]())).withSelfRel()
)).getContent(),
new PageMetadata([Link](), [Link](),
[Link]()),

linkTo(methodOn([Link]).getAllUsers(pageable)).withSelfRel(),

21 / 62
[Link] 2026-05-07

linkTo(methodOn([Link]).getAllUsers([Link]())).withRel("n
ext"),

linkTo(methodOn([Link]).getAllUsers([Link]())).withRe
l("prev")
);
}

Vantaggi di HATEOAS:

Decoupling: Il client non deve conoscere hardcoded gli URL; li scopre dal server.
Flessibilità: Il server può cambiare gli URL senza rompere i client.
Discoverability: I client possono scoprire le operazioni disponibili navigando i link.
API auto-descrittiva: La risposta contiene istruzioni su come procedere.

Svantaggi di HATEOAS:

Complessità: Le response sono più verbose e complesse.


Overhead: Aggiunge payload extra alle risposte.
Curva di apprendimento: Richiede uno sforzo maggiore per client e server.
Adoption lenta: Non tutte le API REST lo utilizzano completamente.

Quando usare HATEOAS:

API pubbliche che devono essere stabili nel tempo.


Client web dinamici che possono navigare i link.
Applicazioni con flussi complessi e molteplici operazioni.

Quando evitare HATEOAS:

API interne o per client mobili con banda limitata.


API ad alta performance dove ogni byte conta.
Prototipi veloci dove la complessità non è giustificata.

Principales Takeaway

Spring Boot elimina il "boilerplate" di Spring tramite auto-configuration e convention-over-


configuration.
Starters semplificano la gestione delle dipendenze.
Testing è integrato nativamente con @SpringBootTest e test slices.
Actuator fornisce osservabilità "pronta all'uso".
Fat JAR rende il deployment cloud-friendly e containerizzabile (come in Docker).

3. Docker e Containerizzazione
Docker è un insieme di strumenti e un ambiente di esecuzione per la virtualizzazione a livello di sistema
operativo. Permette di creare, gestire ed eseguire dei "pacchetti" software chiamati container.

22 / 62
[Link] 2026-05-07

Perché Docker?

Isolamento: Ogni container è isolato dal resto del sistema, potendo accedere solo alle risorse
autorizzate (CPU, memoria, storage).
Consistenza: Garantisce che il software funzioni in modo uniforme indipendentemente
dall'infrastruttura sottostante ("it works on my laptop!" non è più un problema).
Leggerezza: A differenza delle macchine virtuali, i container condividono il kernel del sistema operativo
ospite, rendendoli molto più leggeri e rapidi da avviare.

Componenti Fondamentali

Docker Engine: L'ambiente di runtime che permette l'esecuzione dei container. Si basa su containerd e
runc.
Containerd: È un runtime di container standard del settore, creato con un'enfasi su semplicità,
robustezza e portabilità. Gestisce l'intero ciclo di vita dei container, inclusi il trasferimento delle
immagini, l'esecuzione dei container e lo storage. Donato alla Cloud Native Computing Foundation
(CNCF), implementa la Kubernetes Container Runtime Interface (CRI), rendendolo compatibile sia con
Docker Engine che direttamente con Kubernetes.

23 / 62
[Link] 2026-05-07

Immagini: Template di sola lettura, standalone ed eseguibili che contengono tutto il necessario per far
girare l'applicazione (codice, runtime, librerie, impostazioni).
Layer (Livelli): Ogni immagine è composta da una serie di layer a sola lettura generati dai
comandi del Dockerfile. Grazie ai union file system (come Overlay2), questi layer possono essere
riutilizzati da più immagini, risparmiando spazio su disco e riducendo i tempi di build.

24 / 62
[Link] 2026-05-07

- **Nomi e Tag:** Un'immagine è identificata da un nome (es. `fedora/httpd`) e


opzionalmente da un tag (es. `:version1.0`). Il tag permette di distinguere
diverse versioni della stessa immagine. Se non specificato, Docker utilizza il tag
`latest` per impostazione predefinita. Il formato completo può includere
l'hostname di un registry (es. `[Link]/myimage:v1`).

Container: Istanze runtime delle immagini. Ogni container aggiunge un layer leggibile/scrivibile sopra i
layer a sola lettura dell'immagine originale. Sono più leggeri delle macchine virtuali perché condividono
il kernel dell'host ed eseguono processi isolati nello spazio utente.

Dockerfile: File di testo contenente le istruzioni per costruire un'immagine.

FROM: Specifica l'immagine di base.


RUN: Esegue comandi per creare nuovi layer (es. installazione pacchetti).
COPY / ADD: Copia file locali nell'immagine.
CMD / ENTRYPOINT: Definiscono il comando di avvio del container.
ARG (Build Arguments): Variabili utilizzabili esclusivamente durante la fase di build
dell'immagine. Possono avere valori predefiniti nel Dockerfile o essere passate tramite il
comando docker build --build-arg nome=valore. Non sono disponibili dopo che
l'immagine è stata costruita.
ENV (Environment Variables): Variabili d'ambiente disponibili sia durante la build che durante
l'esecuzione del container (run-time). Possono essere impostate nel Dockerfile e sovrascritte al
momento dell'avvio con docker run -e o nel file [Link]. Spesso si usano i valori
di ARG per impostare i default delle variabili ENV.

Registry: Repository dove vengono archiviate le immagini (es. Docker Hub).

Architettura e Strumenti

Client-Server: Il client Docker comunica con il demone (dockerd) tramite REST API.
Docker Compose: Strumento per definire e gestire applicazioni multi-container tramite file YAML.
Permette di avviare l'intero stack tecnologico con un unico comando.
Comandi principali:
docker-compose up: Crea e avvia i container definiti nel file YAML (usa -d per il
background).
docker-compose down: Ferma e rimuove i container, le reti e le immagini definite.
docker-compose build: Costruisce o ricostruisce i servizi.
docker-compose logs: Visualizza i log di tutti i servizi gestiti.
docker-compose ps: Elenca lo stato dei container gestiti dal file compose.

Orchestrazione con Docker Swarm e Stacks

Docker include funzionalità native di orchestrazione per gestire cluster di macchine:

Docker Swarm: Trasforma un gruppo di motori Docker in un unico motore virtuale. Introduce il
concetto di Service (astrazione superiore al container), permettendo di gestire repliche, bilanciamento
del carico e health check.
Stacks: Una collezione di servizi che compongono un'applicazione in un ambiente specifico.
25 / 62
[Link] 2026-05-07

Si utilizza il comando docker stack deploy -c [Link] nome_stack.


A differenza di Docker Compose, docker stack ignora l'istruzione build e richiede immagini
già esistenti (pre-built), risultando più adatto alla produzione che allo sviluppo.
Differenza Chiave: Docker Compose è ideale per lo sviluppo locale, mentre Docker Swarm/Stacks sono
progettati per il deployment e la scalabilità in ambienti distribuiti.

Integrazioni e Alternative

Kubernetes (K8s): Le versioni recenti di Docker includono un server e un client Kubernetes standalone
(single-node) per test locali. Quando abilitato, permette di distribuire carichi di lavoro in parallelo su
Kubernetes, Swarm o come container classici.

Buildpacks: Un'alternativa all'uso del Dockerfile per la creazione di immagini. Nati da Heroku nel 2011
e ora parte della CNCF, permettono di trasformare il codice sorgente in immagini container in modo
automatizzato senza scrivere istruzioni manuali di build.

Persistenza dei Dati (Volumi e Mount Points): Poiché i container sono effimeri e perdono i dati alla
rimozione, Docker fornisce meccanismi per la persistenza:

Volumi: Gestiti interamente da Docker nell'area di storage specifica del daemon. Sono il modo
raccomandato per persistere dati.
Bind Mounts: Mappano un file o una directory dell'host (macchina locale) all'interno del
container. Sono utili per condividere codice sorgente in fase di sviluppo.

Port Forwarding: Mapping tra porte della macchina host e del container tramite l'opzione -p (es. -p
8080:80). Questo permette all'applicazione di essere accessibile dall'esterno (es. tramite l'interfaccia
[Link] o un IP esterno).

Networking: Il sottosistema di rete di Docker è pluggable e utilizza diversi driver:

bridge: Il driver di rete predefinito. Le reti user-defined bridge sono preferibili a quella di
default perché permettono ai container di risolversi reciprocamente tramite nome/alias (anziché
solo tramite IP).
host: Rimuove l'isolamento di rete tra il container e l'host Docker.
overlay: Collega più demoni Docker tra loro (usato in cluster come Docker Swarm).
none: Disabilita completamente il networking per il container.
Comandi utili: docker network create, docker network ls, docker network connect.

26 / 62
[Link] 2026-05-07

Workflow Principale

1. Build: docker build -t nome_immagine . crea l'immagine dal Dockerfile.


2. Pull/Push: docker pull scarica immagini dal registry; docker push le carica.
3. Run: docker run -it nome_immagine avvia un container dall'immagine.
4. Exec: docker exec -it <container> bash permette di entrare in un container in esecuzione.

3.A Docker Assignment – Mini Riassunto

A1. Docker CLI e HTTPD

2.1 Hello world

Cercata e scaricata l’immagine hello-world con docker pull.


Eseguita con docker run hello-world per verificare l’installazione Docker.

2.2 HTTPD Web-server

Avviato primo container:


docker run -d --name myhttp1 -p 80:80 httpd
Collegato al container, installato nano e modificato /usr/local/apache2/htdocs/[Link].

2.3 Multiple HTTPD instances

Creata cartella mysite sul host con un [Link] personalizzato.


Avviato secondo container:
docker run -d --name myhttp2 -p 8080:80 -v
"ABS_PATH/mysite:/usr/local/apache2/htdocs/" httpd
Entrambi accessibili: [Link] (myhttp1) e [Link] (myhttp2).

27 / 62
[Link] 2026-05-07

2.4 General maintenance

Controllo container: docker ps, docker ps -a.


Stop dei container attivi: docker stop ....
Pulizia container fermi: docker rm ... o docker container prune.

A2. Dockerfile – Generatore di [Link]

3.1 [Link] file generator

Creato script [Link] che ogni secondo scrive data e ora in /data/[Link] con un
loop infinito.

Creato Dockerfile:

FROM alpine
COPY [Link] /[Link]
VOLUME ["/data"]
CMD ["/[Link]"]

Build immagine: docker build -t testmyimage .

3.2 Shared /data directory

Creato volume nominato: docker volume create shareddata.


Avviato generator con volume:
docker run -d --name generator -v shareddata:/data testmyimage

3.3 Test environment con httpd

Avviato provider httpd condividendo lo stesso volume:


docker run -d --name provider -p 8080:80 -v
shareddata:/usr/local/apache2/htdocs/ httpd
Su [Link] si vede la data/ora aggiornate.

A3. Docker Compose e Docker Stack

Creato [Link] che definisce:

httpd1 su 80:80 (pagina default).


httpd2 su 8080:80 con bind mount ./mysite:/usr/local/apache2/htdocs/.
generator con immagine testmyimage e volume shared-data:/data.
provider con httpd e volume shared-data:/usr/local/apache2/htdocs/.

Test con Docker Compose:

Avvio: docker-compose up -d
Log: docker-compose logs
Stop/cleanup: docker-compose down, docker-compose stop/start.

28 / 62
[Link] 2026-05-07

Docker Stack:

Inizializzato Swarm: docker swarm init.


Deploy stack: docker stack deploy -c [Link] mystack.

A4. Dockerizzare la REST API (Spring Boot)

Progetto Maven Spring Boot buildato con:

./mvnw clean package

Jar prodotto in target/[Link].

Creato Dockerfile nella root del progetto:

FROM eclipse-temurin:XX (JRE/JDK compatibile)


WORKDIR /app
COPY target/[Link] /app/[Link]
ENTRYPOINT ["java","-jar","/app/[Link]"]

Build immagine: docker build -t demo-rest .

Run container: docker run -p 8080:8080 demo-rest


(API accessibile su [Link]

A5. Buildpacks

Usato il plugin Spring Boot (Cloud Native Buildpacks) per generare l’immagine automaticamente.

Comando Maven wrapper:

./mvnw spring-boot:build-image

L’immagine è stata creata con nome basato su artifactId:version.

Test esecuzione:

docker run -p 8080:8080 <nome-immagine-buildpacks>

L’app REST è risultata funzionante senza Dockerfile esplicito.

Workflow di Sviluppo Generico

Utilizzo di Spring Initializr ([Link]) per generare rapidamente lo scheletro dell'applicazione.


Configurazione tramite Annotazioni Java anziché file XML complessi.
Integrazione facilitata con database (es. H2) e JPA per la persistenza dei dati.

4. Introduction to DevOps

29 / 62
[Link] 2026-05-07

DevOps è un approccio culturale, organizzativo e tecnico che unisce sviluppo software (Dev) e
operation/infrastruttura (Ops) per rilasciare software in modo più rapido, stabile e ripetibile.

Obiettivi Principali

Ridurre il time-to-market: consegnare valore agli utenti più frequentemente.


Aumentare affidabilità e qualità: meno errori in produzione e recovery più veloce.
Migliorare collaborazione: abbattere i silos tra team di sviluppo, operation, QA e sicurezza.

Dal Modello Tradizionale a DevOps

Modello tradizionale: sviluppo e operation lavorano separati, con handoff lenti e conflitti di
responsabilità.
DevOps: responsabilità condivisa lungo tutto il ciclo di vita applicativo (build, test, release,
monitoraggio, feedback).

Principi Chiave (Cultura DevOps)

Collaboration & Shared Ownership: i team condividono obiettivi, metriche e responsabilità.


Automation First: automatizzare attività ripetitive riduce errori manuali e tempi.
Continuous Improvement: piccoli miglioramenti continui basati su metriche e feedback reali.
Fail Fast, Learn Faster: individuare presto i problemi e imparare rapidamente.

CALMS Model

Un modello usato per descrivere le dimensioni di DevOps:

C - Culture: collaborazione, fiducia, responsabilità condivisa.


A - Automation: pipeline CI/CD, test automatici, provisioning automatico.
L - Lean: riduzione sprechi, piccoli batch, flusso continuo.
M - Measurement: monitoraggio di performance, qualità e affidabilità.
S - Sharing: condivisione di conoscenza, pratiche e strumenti.

CI, CD e Pipeline

Continuous Integration (CI): integrazione frequente del codice con build e test automatici.
Continuous Delivery: artefatti sempre pronti al rilascio in produzione.
Continuous Deployment: ogni modifica valida viene rilasciata automaticamente.

Una pipeline tipica include:

1. Commit su repository Git.


2. Build automatica.
3. Test automatici (unit/integration).
4. Analisi qualità e sicurezza.
5. Packaging e deploy (staging/produzione).
6. Monitoraggio post-rilascio e feedback.

Infrastructure as Code (IaC)

30 / 62
[Link] 2026-05-07

L'infrastruttura viene definita come codice versionato.


Permette ambienti coerenti, replicabili e auditabili.
Riduce configurazioni manuali e drift tra ambienti (dev/test/prod).

Monitoring, Logging e Observability

Monitoring: misura stato e prestazioni (CPU, memoria, latenza, errori).


Logging: raccolta eventi applicativi e di sistema per diagnosi.
Observability: capacità di capire rapidamente perché un sistema si comporta in un certo modo.

Metriche DevOps (DORA)

Deployment Frequency: frequenza dei rilasci.


Lead Time for Changes: tempo dal commit al deploy in produzione.
Change Failure Rate: percentuale di rilasci che causano incidenti.
Mean Time to Restore (MTTR): tempo medio per ripristinare il servizio.

DevSecOps

La sicurezza viene integrata fin dall'inizio del ciclo di sviluppo.


Controlli di sicurezza automatizzati in pipeline (dependency scan, static analysis, image scan).
Obiettivo: sicurezza continua senza rallentare la delivery.

Benefici Attesi

Rilasci più frequenti e prevedibili.


Migliore qualità software.
Riduzione dei costi operativi nel lungo periodo.
Maggiore resilienza dei sistemi.

Toolchain Tipica (Esempi)

Versioning: Git, GitHub/GitLab.


CI/CD: GitHub Actions, Jenkins, GitLab CI.
Containerizzazione: Docker.
Orchestrazione: Kubernetes.
IaC: Terraform, Ansible.
Monitoring/Logging: Prometheus, Grafana, ELK.

Concetto Chiave Finale

DevOps non è solo un insieme di strumenti: è una cultura operativa che combina persone, processi e
automazione per fornire software di qualità in modo continuo.

5. CI/CD – Continuous Integration e Continuous Delivery/Deployment


Definizione

31 / 62
[Link] 2026-05-07

Acronimo Definizione

CI Continuous Integration – integrazione frequente del codice + build + test automatici

CD Continuous Delivery – il software è sempre pronto al rilascio in produzione

Continuous Deployment – ogni modifica valida viene rilasciata automaticamente senza


CD
intervento umano

Continuous Integration (CI)

L'obiettivo è rilevare i problemi di integrazione il prima possibile:

Gli sviluppatori integrano il codice nel branch condiviso frequentemente (più volte al giorno).
Ogni push scatena automaticamente: build + test.
Se build o test falliscono, il team viene notificato immediatamente.
Principio chiave: non lasciare il branch principale in stato "broken" a lungo.

Pratiche essenziali di CI

Version Control (VCS): tutto il codice (inclusa config e IaC) è versionato in Git.
Automated Build: processo di build riproducibile e automatizzato (Maven, Gradle, npm…).
Automated Testing: test unitari e di integrazione eseguiti ad ogni commit.
Fast Feedback: la pipeline deve essere rapida (~10 minuti) per non bloccare il flusso.
Single Source of Truth: un solo repository, un solo processo di build.

Continuous Delivery

Il codice è sempre in uno stato rilasciabile ("deployable at any time").


Il deploy in produzione richiede una decisione umana (approvazione manuale).
Gli artefatti prodotti (es. .jar, immagine Docker) sono pronti e validati in staging prima di andare in
prod.

Continuous Deployment

Estensione della Continuous Delivery: il deploy avviene automaticamente dopo che i test in staging
sono superati.
Richiede alta fiducia nella copertura dei test e nei processi di rollback.
Adatto a organizzazioni mature con molti rilasci al giorno (es. Netflix, Amazon).

32 / 62
[Link] 2026-05-07

La Pipeline CI/CD

Una pipeline è una sequenza di step automatizzati che portano il codice dal repository alla produzione:

Commit → Build → Test → Analisi Qualità → Packaging → Deploy Staging → (Approval)


→ Deploy Prod → Monitor

Stage tipici

1. Source: trigger su push/merge request.


2. Build: compilazione e risoluzione dipendenze.
3. Unit Test: test veloci e isolati.
4. Integration Test: test che coinvolgono più componenti o database.
5. Static Analysis / Code Quality: SonarQube, linting, coverage minima.
6. Security Scan: analisi dipendenze vulnerabili (es. OWASP Dependency-Check, Trivy per immagini
Docker).
7. Packaging: creazione artefatto (JAR, immagine Docker, etc.).
8. Deploy to Staging: rilascio in ambiente di pre-produzione.
9. Acceptance / Smoke Test: verifica di base sull'ambiente staging.
10. Deploy to Production: manuale (Delivery) o automatico (Deployment).
11. Monitoring & Alerting: osservazione del comportamento post-rilascio.

Artefatti e Registri

Il risultato della build è un artefatto immutabile (es. [Link], immagine Docker taggata).

33 / 62
[Link] 2026-05-07

Gli artefatti vengono archiviati in un registry (es. Docker Hub, Nexus, Artifactory).
Lo stesso artefatto viene promosso tra gli ambienti (dev → staging → prod) senza essere ricostruito.

Branching Strategy e CI

Trunk-Based Development: tutti i developer lavorano su branch a vita breve e integrano spesso nel
branch principale. Favorisce la CI.
Feature Branch: ogni funzionalità vive su un branch separato; la CI viene eseguita su ogni branch prima
del merge.
GitFlow: modello strutturato con branch main, develop, feature/*, release/*, hotfix/*. Più
complesso, meno frequente nella CI pura.

GitHub Actions (Esempio Pratico)

GitHub Actions è uno strumento CI/CD integrato in GitHub. Definisce la pipeline tramite file YAML in
.github/workflows/:

name: CI Pipeline

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: ./mvnw clean package
- name: Run Tests
run: ./mvnw test
- name: Build Docker image
run: docker build -t my-app:${{ [Link] }} .

Concetti chiave di GitHub Actions

Workflow: pipeline definita in un file YAML.


Event (on): evento che scatena il workflow (push, pull_request, schedule…).
Job: insieme di step eseguiti su uno stesso runner.
Step: singola operazione (run di un comando o uso di un'action pre-costruita).
Runner: macchina virtuale che esegue i job (GitHub-hosted o self-hosted).

34 / 62
[Link] 2026-05-07

Action: unità riutilizzabile di automazione (es. actions/checkout, actions/setup-java).


Secret: variabile cifrata per credenziali (es. ${{ secrets.DOCKER_PASSWORD }}).

GitLab CI/CD (Esempio Pratico)

GitLab CI/CD è integrato direttamente in GitLab e usa il file .[Link] nella root del repository.

stages:
- build
- test
- package

variables:
MAVEN_OPTS: "-[Link]=.m2/repository"

cache:
paths:
- .m2/repository

build_job:
stage: build
image: maven:3.9.9-eclipse-temurin-17
script:
- mvn -B clean compile

test_job:
stage: test
image: maven:3.9.9-eclipse-temurin-17
script:
- mvn -B test
artifacts:
when: always
reports:
junit:
- target/surefire-reports/*.xml

package_job:
stage: package
image: maven:3.9.9-eclipse-temurin-17
script:
- mvn -B package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 week
only:
- main

Concetti chiave di GitLab CI/CD

Pipeline: insieme completo dei job eseguiti per un commit o merge request.
35 / 62
[Link] 2026-05-07

Stages: macro-fasi ordinate (build, test, deploy...). I job nello stesso stage possono girare in parallelo.

Job: unità base che esegue script shell.

Runner: agente che esegue i job (shared o specifico del progetto).

Artifacts: file prodotti da un job e riutilizzabili negli step successivi (es. jar, report test).

Cache: accelera la pipeline riusando dipendenze tra esecuzioni.

Variables/Secrets: parametri e credenziali gestite in modo centralizzato nelle CI/CD settings.

Rules/Only/Except: controllo condizionale su quando eseguire un job (branch, tag, merge request,
variabili).

Variabili predefinite (GitLab CI/CD)

GitLab espone automaticamente molte variabili di ambiente utili nei job, senza doverle definire manualmente.

Variabile Significato Esempio d'uso

CI Indica che il job gira in ambiente CI (true) Check rapido in script

CI_PIPELINE_ID ID univoco della pipeline Versionare artefatti

Origine trigger (push, merge_request_event,


CI_PIPELINE_SOURCE Condizioni in rules
schedule, web...)

CI_JOB_ID ID univoco del job corrente Logging e tracing

CI_JOB_STAGE Stage del job (build, test...) Script condizionali

CI_COMMIT_SHA SHA completo del commit Tag immagine Docker

CI_COMMIT_SHORT_SHA SHA corto del commit Nomi artefatti leggibili

CI_COMMIT_BRANCH Branch corrente (se pipeline su branch) Deploy per branch

CI_COMMIT_TAG Tag corrente (se pipeline su tag) Release pipeline

Regole su branch
CI_DEFAULT_BRANCH Branch principale del progetto
default

Naming
CI_PROJECT_PATH Namespace/progetto (group/project)
immagini/registry

CI_PROJECT_DIR Path locale del repository sul runner Script file-system

CI_REGISTRY URL del Container Registry GitLab Login Docker

Push immagine
CI_REGISTRY_IMAGE Nome completo immagine registry del progetto
versionata

CI_RUNNER_DESCRIPTION Descrizione del runner che esegue il job Debug infrastruttura

Esempio pratico in .[Link]:

36 / 62
[Link] 2026-05-07

docker_build:
stage: package
script:
- echo "Pipeline: $CI_PIPELINE_ID"
- echo "Commit: $CI_COMMIT_SHORT_SHA"
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

Nota: le variabili predefinite sono diverse dalle variabili custom e dai secret definiti nel progetto/gruppo.
Quelle sensibili (token, password, chiavi) vanno sempre salvate come variabili protette/masked nelle
impostazioni CI/CD.

Differenze rapide: GitHub Actions vs GitLab CI/CD

File pipeline: .github/workflows/*.yml (GitHub) vs .[Link] (GitLab).


Unità di orchestrazione: workflow/job/step (GitHub) vs pipeline/stage/job (GitLab).
Ecosistema: GitHub privilegia marketplace di actions; GitLab integra molte funzioni DevOps nella stessa
piattaforma.

Approfondimento: Jobs

Un job è l'unità atomica di lavoro della pipeline: esegue una lista di comandi su un runner e produce uno
stato finale (success, failed, canceled, skipped).

Ciclo di vita di un Job

1. Scheduling: il sistema decide quando avviarlo in base a stage/rules/dependencies.


2. Provisioning runner: viene allocato il runner (VM/container).
3. Setup ambiente: checkout codice, variabili, cache.
4. Execution: esecuzione di script/step.
5. Post-job: upload artifacts/report, cleanup workspace.
6. Outcome: il risultato impatta i job successivi e lo stato globale pipeline.

Proprietà importanti di un Job (GitLab)

stage: macro-fase in cui gira il job.


script: comandi principali.
image: immagine container usata per eseguire il job.
rules / only / except: condizioni di esecuzione.
needs: dipendenze dirette tra job (grafo DAG, meno attese).
artifacts: file da conservare/passare ad altri job.
cache: ottimizzazione performance (dipendenze riutilizzabili).
retry / timeout / allow_failure: resilienza e controllo errori.
when: manual: job avviabile manualmente (es. deploy produzione).

37 / 62
[Link] 2026-05-07

Esempio GitLab con dipendenze e controllo flusso

stages: [build, test, security, package, deploy]

build_job:
stage: build
script:
- mvn -B clean compile
artifacts:
paths: [target/]

unit_test_job:
stage: test
needs: [build_job]
script:
- mvn -B test

security_scan_job:
stage: security
needs: [build_job]
script:
- echo "Eseguo dependency scan"
allow_failure: true

package_job:
stage: package
needs: [unit_test_job]
script:
- mvn -B package -DskipTests
artifacts:
paths: [target/*.jar]
expire_in: 1 week

deploy_prod_job:
stage: deploy
needs: [package_job]
script:
- echo "Deploy in produzione"
when: manual
only:
- main

Esempio GitHub Actions con needs e matrix

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./mvnw -B clean compile
38 / 62
[Link] 2026-05-07

test:
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
java: [17, 21]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: ${{ [Link] }}
distribution: temurin
- run: ./mvnw -B test

package:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./mvnw -B package -DskipTests

Best Practice sui Jobs

Mantieni job piccoli e focalizzati (single responsibility).


Usa nomi chiari (build_app, test_unit, deploy_prod).
Riduci la durata con cache, esecuzione parallela e immagini leggere.
Separa job critici da job informativi (allow_failure solo dove ha senso).
Conserva artifacts minimi necessari; imposta expire_in ragionevole.
Usa needs per evitare attese inutili tra stage.
Proteggi i job di deploy con branch protetti, approval manuale e secret scoped.
Rendi i job idempotenti: rilanciabili senza effetti collaterali imprevedibili.

Testing nella Pipeline

Tipo di Test Velocità Scope Dove in Pipeline

Unit Test Velocissimo Singola classe/funzione Dopo ogni build

Integration Test Medio Più componenti, DB Dopo unit test

End-to-End Test Lento Intero sistema Ambiente staging

Performance/Load Test Lento Scalabilità Pre-prod

Quality Gates

Un quality gate blocca la pipeline se alcune soglie non sono rispettate:

Copertura del codice (code coverage) < X%.


Presenza di bug critici o vulnerabilità.

39 / 62
[Link] 2026-05-07

Violazioni di regole stilistiche.


Strumento tipico: SonarQube.

Rollback e Recovery

In Continuous Deployment è fondamentale avere un meccanismo di rollback rapido.


Strategie comuni:
Re-deploy dell'artefatto precedente.
Blue/Green Deployment: due ambienti identici (blue = attivo, green = nuovo). Il traffico viene
spostato su green; in caso di problemi si torna a blue.
Canary Release: il nuovo codice viene esposto a una piccola percentuale di utenti prima del
rilascio completo.
Feature Flags: le funzionalità possono essere abilitate/disabilitate a runtime senza deploy.

Vantaggi CI/CD

Rilascio software più rapido e frequente.


Rilevazione precoce dei bug (più economico correggerli).
Riduzione del rischio dei rilasci (batch piccoli).
Feedback continuo agli sviluppatori.
Documentazione implicita del processo di build tramite codice YAML.

Strumenti CI/CD più Comuni

Strumento Tipo

GitHub Actions CI/CD integrato in GitHub

GitLab CI/CD CI/CD integrato in GitLab

Jenkins Open-source, self-hosted

CircleCI Cloud-based

Azure Pipelines Microsoft Azure

ArgoCD GitOps per Kubernetes

5.A CI/CD Assignment – Mini Riassunto

A1. Prerequisiti

1.1 Creato account GitLab e progetto, clonato il repo e copiato il progetto Java Spring Boot.
1.2 Creato deploy token su GitLab (Settings → Repository → Deploy tokens) con scope
read_registry e username kubernetes-gitlab.
1.3 Creato cluster GKE su Google Cloud (us-central1-a, 1 nodo e2-medium).
1.4 Creato Kubernetes secret per autorizzare GKE a pullare immagini dal registry GitLab:

kubectl create secret docker-registry secret-gitlab \


--docker-server=[Link] \
--docker-username=kubernetes-gitlab \
40 / 62
[Link] 2026-05-07

--docker-password=<deploy-token> \
--docker-email=<email>

A2. .[Link] e stages

Creato file .[Link] nella root del progetto con 3 stage in ordine: test → build → deploy.

A3. Test stage

Due job paralleli che testano il progetto Maven con JDK17 e JDK21. Risolto problema di permessi su mvnw con:

git update-index --chmod=+x mvnw

A4. Build stage

Job che builda l'immagine Docker e la pusha sul GitLab Container Registry usando docker:dind. Pushata sia
con tag $CI_COMMIT_SHORT_SHA che con tag latest.

A5. Deploy stage

Due job di deploy su GKE usando l'immagine google/cloud-sdk:

staging: deploy automatico su branch dev (continuous delivery)


production: deploy manuale su branch main (when: manual)

Creati manifest Kubernetes in k8s/:

[Link]: Deployment con 1 replica, immagine dal registry GitLab, imagePullSecrets:


secret-gitlab
[Link]: Service di tipo LoadBalancer porta 80 → 8080

Variabile GCP_SERVICE_KEY aggiunta in Settings → CI/CD → Variables con il JSON della service account
GCP.

A6. Run pipeline

Push su branch dev → pipeline parte automaticamente con i 3 stage in sequenza. IP esterno dell'app verificato
con:

kubectl get service demo-service

6. Kubernetes – Riassunto Completo (dal PDF)


Cos'è Kubernetes e perché si usa

41 / 62
[Link] 2026-05-07

Kubernetes (K8s) è una piattaforma open-source per distribuire, mantenere e scalare applicazioni
containerizzate.

Sta tra IaaS e PaaS: offre astrazioni di alto livello (deploy, scaling, self-healing) senza togliere flessibilità
infrastrutturale.
Non è un PaaS monolitico: fornisce building blocks componibili.
Non è solo “orchestrazione sequenziale” (A → B → C): lavora a stato desiderato con controller
indipendenti che riconciliano continuamente lo stato reale.

Cenni storici essenziali

Nato in Google, annunciato nel 2014.


Fortemente ispirato a Borg, il cluster manager interno di Google.
Versione 1.0 rilasciata il 21 luglio 2015.
Nome “Kubernetes” dal greco: timoniere/capitano/governatore.

Architettura del cluster

Un cluster Kubernetes è un insieme di nodi (da 1 a migliaia), fisici o virtuali.

Control Plane (master): gestisce il cluster, prende decisioni globali, espone le API.
Worker Nodes: eseguono i workload (container dentro Pod).

In molti contesti il nodo control plane può anche eseguire workload, ma in produzione si tende a separare i
ruoli.

Control Plane: componenti chiave

1. kube-apiserver: front-end API di Kubernetes.


2. etcd: key-value store consistente e altamente disponibile (stato del cluster).
3. kube-scheduler: assegna i Pod ai nodi disponibili.
4. kube-controller-manager: esegue i loop di controllo per allineare stato reale e stato desiderato.
5. cloud-controller-manager: integra logica cloud-specifica (LB, nodi, route, ecc.).

Data Plane (worker): componenti chiave

1. kubelet: agente del nodo, assicura che i Pod richiesti siano in esecuzione.
2. kube-proxy: gestisce le regole di rete e l'accesso ai servizi.
3. cAdvisor: raccoglie metriche e informazioni di utilizzo/performance dei container.

Pod: unità minima di deploy

In Kubernetes non si deploya “il container da solo”: si deploya un Pod.

Un Pod contiene almeno un container.


I container nello stesso Pod condividono:
IP locale
namespace di rete locale
possibilità di condividere volumi/config/secrets
I container nello stesso Pod non possono esporre la stessa porta.

42 / 62
[Link] 2026-05-07

Regola pratica:

One Pod, one service (quasi sempre).


Multi-container Pod solo quando i container collaborano sulla stessa applicazione.

Perché usare più container nello stesso Pod

Caso tipico: pattern “main + helper”.

Esempio: app principale + container per forwarding log verso collector centrale.
Vantaggi: separazione responsabilità, fault isolation del componente ausiliario.

Multi-container Pod Design Patterns

1. Init container

Esegue operazioni di inizializzazione prima dei container applicativi.


Deve terminare con successo prima dello startup del main container.

2. Sidecar container

Container di supporto al main (logging, monitoring, sync, watchers).


Vive e muore insieme al Pod.

3. Adapter container

Variante del sidecar.


Normalizza/trasforma output eterogeneo dell'app in formato standard (es. metriche/log).

4. Ambassador container

Proxy locale che disaccoppia l'app dalle dipendenze esterne.


L'app parla sempre con localhost; l'ambassador instrada verso endpoint diversi per ambiente.

Oggetti Kubernetes ed ETCD

In Kubernetes tutto è un oggetto (Pod, Service, Deployment, ConfigMap, Secret, ecc.).

Ogni oggetto ha:

metadata (nome, namespace, label, ecc.)


spec (stato desiderato)
status (stato osservato corrente)

Gli oggetti sono persistiti in etcd.

Due modalità di creazione oggetti

1. Imperativa

Comandi CLI/API diretti (kubectl run, kubectl create, ...).


Rapida per test, meno governabile nel tempo.

43 / 62
[Link] 2026-05-07

2. Dichiarativa (preferita)

Manifest YAML/JSON versionabili.


Maggiore ripetibilità, auditabilità, collaborazione e automazione.

Manifest Kubernetes: struttura minima

Ogni manifest include almeno:

apiVersion
kind
metadata
spec

Esempio minimale:

apiVersion: v1
kind: Pod
metadata:
name: rss-site
labels:
app: web
spec:
containers:
- name: front-end
image: nginx
ports:
- containerPort: 80

Imperative vs Declarative (in sintesi)

Imperative: descrivi i passaggi da eseguire.


Declarative: descrivi il risultato desiderato.

Con il modello dichiarativo Kubernetes:

applica loop di riconciliazione continui (watch loops)


abilita self-healing e scaling più naturali
si integra meglio con GitOps, CI/CD e controllo versione

Kubernetes vs PaaS tradizionale

Kubernetes offre funzionalità tipiche PaaS (deploy, scaling, LB, monitoring/logging), ma:

non impone un unico stack


non nasconde completamente l'infrastruttura
lascia libertà di scelta su runtime, networking, security, observability

Takeaway da ricordare per l'esame

44 / 62
[Link] 2026-05-07

1. Kubernetes è una piattaforma a stato desiderato, non un semplice orchestratore sequenziale.


2. Il cluster è diviso in control plane e worker/data plane.
3. L'unità base di deploy è il Pod, non il container.
4. Multi-container Pod solo per pattern specifici (init, sidecar, adapter, ambassador).
5. L'approccio corretto in team è manifest dichiarativo versionato.
6. etcd è il cuore dello stato del cluster.

Comandi utili (ripasso rapido)

# vedere i nodi
kubectl get nodes

# vedere i pod
kubectl get pods

# applicare manifest dichiarativo


kubectl apply -f [Link]

# descrivere risorsa
kubectl describe pod <pod-name>

# logs del container


kubectl logs <pod-name>

Domande demo Kubernetes (pag. 52-74) - riassunto guidato

1. Demo 52 - Creating a Pod Si crea un Pod con manifest YAML (kubectl apply -f ...). Kubernetes
legge il file come stato desiderato e prova ad allineare il cluster.

2. Question 53 - Cosa succede se applico due volte lo stesso manifest? kubectl apply e
idempotente: se lo stato e gia uguale, non cambia nulla e non crea duplicati.

3. Question 53 - Cosa succede se modifico il manifest e lo riapplico? Kubernetes confronta stato


attuale e nuovo stato desiderato, poi applica le differenze. Se una modifica non e applicabile a caldo
(campo immutabile), puo servire delete + recreate della risorsa.

4. Pod Details (55) Ogni Pod ha IP unico nel cluster. Il Pod puo esporre volumi ai container interni. I Pod
possono essere gestiti direttamente via API oppure tramite controller.

5. Demo 56 - Updating a Pod L'aggiornamento avviene con la stessa logica dichiarativa: si cambia il
manifest e si riapplica; Kubernetes riconcilia lo stato.

6. Question 58 - Come vengono allocate CPU e memoria ai Pod? Di default le risorse sono condivise
tra Pod sul nodo. Se la memoria fisica non basta, un Pod puo essere terminato con OOM (Out Of
Memory).

7. CPU allocation (60) Kubernetes usa CFS (Completely Fair Scheduler): il tempo CPU e diviso in slice
(tipicamente 100 ms) e distribuito equamente. Se un Pod esaurisce la quota, viene rallentato fino alla
slice successiva.

45 / 62
[Link] 2026-05-07

8. Question 61 + Answer 62 - App CPU-intensive o memory-sensitive: cosa fare? Si definiscono


[Link] (minimo garantito) e, se necessario, [Link] (massimo consentito)
per container/Pod.

9. Pod resource requests (63-66)

memory: "64Mi" = memoria minima garantita.


cpu: "250m" = 0.25 core garantiti.
Lo scheduler avvia il Pod solo su nodi che soddisfano le richieste.
Se nessun nodo ha risorse sufficienti, il Pod non parte.
Se il nodo ha risorse libere, il Pod puo usare anche piu del richiesto.

10. Question 67 + Answer 68 - Come evitare che un Pod consumi tutto? Si impostano i limits (es.
memory/cpu) per impedire che un singolo Pod monopolizzi il nodo.

11. Pod memory limits (69) Il limite memoria e enforced dal kernel in modo reattivo: quando c'e memory
pressure, il container che supera il limite puo essere terminato (OOM kill).

12. Pod CPU limits (70) Il limite CPU e enforced con throttling: e un limite duro, quindi il container non
puo superare la quota CPU definita.

13. Question 72 + Answer 73 - Limite CPU basso ma app multi-thread Anche con piu thread, tutti
condividono la stessa quota totale CPU. Quindi aumenta la concorrenza interna, ma le performance
restano vincolate dal limite complessivo.

14. Slide 74 - Requests and limits setup Requests e limits migliorano stabilita e uso risorse, ma vanno
calibrati con monitoraggio reale dell'applicazione e tuning progressivo.

7. Kubernetes – Part 2
Riassunto completo

Storage persistente in Kubernetes

Anche i Pod hanno storage interno effimero: quando il Pod viene rimosso, i dati locali spariscono.
Lo storage interno del Pod e condiviso tra i container dello stesso Pod.
Per persistere i dati si usano due oggetti:
PersistentVolume (PV): rappresenta storage disponibile nel cluster.
PersistentVolumeClaim (PVC): richiesta di storage fatta da Pod/applicazione.
Kubernetes fa il binding tra PVC e PV compatibile (size, access mode, storage class, tipicamente anche
tipo filesystem/backend).
In cloud e comune il dynamic provisioning: spesso definisci solo il PVC e il volume viene creato
automaticamente.

Access mode e montaggio dei volumi

Gli access mode definiscono da quanti nodi e con quali permessi un PV puo essere montato.
ReadWriteOnce (RWO): lettura/scrittura da un solo nodo alla volta (piu Pod sullo stesso nodo possono
condividerlo).

46 / 62
[Link] 2026-05-07

ReadOnlyMany (ROX): montabile da piu nodi in sola lettura.


ReadWriteMany (RWX): montabile da piu nodi in lettura/scrittura.
In alcuni contesti esiste anche ReadWriteOncePod (RWOP), che limita l'uso in scrittura a un solo Pod
nell'intero cluster.
Nota: il comportamento effettivo dipende anche dal backend di storage e dal CSI driver in uso.
Per usare un PVC in un Pod:
1. lo dichiari in [Link];
2. lo monti nel container con volumeMounts.

Namespaces e organizzazione dei workload

I namespace servono per isolare gruppi di risorse nello stesso cluster (ambienti/logica/team diversi).
Se non specifichi namespace, Kubernetes usa default.
I nomi delle risorse devono essere unici dentro un namespace, non globalmente.
Namespace di sistema tipici: kube-system, kube-public, kube-node-lease.
Il prefisso kube- e riservato ai namespace di sistema (tecnicamente creabili, ma da evitare in pratica).
Comandi utili:
kubectl get namespaces
kubectl get pods -n my-namespace
Risorse:
Namespaced: Pod, PVC, ConfigMap, Secret.
Cluster-wide: PV.

Configurazione dei Pod: env vars e ConfigMap

Le variabili d'ambiente in Kubernetes si definiscono a livello container (env).


Per condividere configurazioni non sensibili tra Pod si usa ConfigMap.
ConfigMap salva coppie chiave-valore testuali (max circa 1 MiB).
Un ConfigMap puo essere consumato:
come env var (configMapKeyRef);
come file montato in un volume (chiave = nome file, valore = contenuto).
Nella pratica, puoi combinare approcci: alcune chiavi come env var e altre come file di configurazione
montati.

Dati sensibili: Secret

47 / 62
[Link] 2026-05-07

Per dati sensibili (password, token, credenziali) si usa Secret.


Sintassi simile a ConfigMap, ma con type (default Opaque).
Tipi comuni: Opaque, [Link]/dockerconfigjson (registry), [Link]/basic-auth,
[Link]/ssh-auth.
Per registry privati si usa un secret docker-registry e nel Pod imagePullSecrets.
Anche i Secret sono namespaced, quindi puoi avere lo stesso nome in namespace diversi.
I Secret non sono mostrati in chiaro nei flussi standard CLI, ma vanno comunque trattati come dati
sensibili.

Probes e salute applicativa

Le probe sono test eseguiti dal kubelet sul container:


Readiness: quando il container e pronto a ricevere traffico.
Liveness: quando il container va riavviato (es. deadlock).
Startup: per app lente in avvio; finche non passa, readiness/liveness non partono.
Tipi di check supportati: exec (shell), tcpSocket, httpGet, grpc.
Readiness gira durante tutto il ciclo di vita: se fallisce, il Pod viene tolto dagli endpoint ma non
necessariamente riavviato.
Liveness non aspetta readiness: se configurata male puo causare restart prematuri; per mitigare si usa
initialDelaySeconds o startup probe.
Startup viene eseguita solo in avvio; quando passa, entrano in gioco readiness/liveness periodiche.

Workload batch: Job e CronJob

I Pod normali sono pensati per processi long-running; se il processo finisce, Kubernetes tende a
riavviarlo.
Per task brevi si usa Job (success/failure basato su exit code).
backoffLimit controlla i retry in caso di errore.
Per esecuzioni pianificate periodiche si usa CronJob (schedule + jobTemplate).
Exit code: 0 = successo, valore non zero = errore.
Il container termina con l'exit code del suo processo di entrypoint; il Pod eredita l'esito del container
principale.
Un Job puo orchestrare anche piu Pod; il successo finale dipende dalla policy configurata.
Nei Job si usa spesso restartPolicy: Never nel template Pod.
I CronJob supportano use case operativi periodici (es. log collection, metric aggregation) e includono
gestione storico/sospensione del planning.

Mappa demo Part 2 (slide-by-slide)

Demo 01: Creating a PersistentVolumeClaim.


Demo 02-03: Share a PVC between Pods.
Demo: Play with namespaces.
Demo 04-05: Configure Pods with environment variables.
Demo 06: Create a ConfigMap.
Demo 07-08: Configure Pods with ConfigMaps.
Demo 09-10: Configure Pods with Secrets.
Demo 11: Configure Pods with probes.

48 / 62
[Link] 2026-05-07

Demo 12: Run a Job.


Demo 13: Run a CronJob.

Domande demo Kubernetes Part 2 - risposta guidata

1. Come persisto i dati oltre il ciclo di vita di un Pod? Definisco storage esterno con PV/PVC: il Pod
monta il claim e i dati restano anche se il Pod viene ricreato.

2. Come condivido un volume tra Pod? Piu Pod possono usare lo stesso PVC; la condivisione reale
dipende da access mode e supporto dello storage backend.

3. Come organizzo migliaia di workload nel cluster? Con i namespace: isolamento logico, naming
separato e gestione per team/ambiente.

4. Come condivido configurazioni non sensibili tra piu Pod? Con ConfigMap, referenziato come env
var o file montato.

5. Come condivido informazioni sensibili (es. credenziali DB)? Con Secret, che e l'oggetto dedicato ai
dati sensibili.

6. Come permetto a un Pod di scaricare immagini da registry privato? Creo secret docker-registry
e lo referenzio in imagePullSecrets nel manifest del Pod.

7. A cosa servono readiness, liveness e startup probe? Readiness controlla il traffico, liveness controlla i
riavvii, startup protegge i container lenti in avvio.

8. Quando uso Job e quando CronJob? Job per esecuzioni una tantum/batch; CronJob per esecuzioni
periodiche pianificate.

9. Che ruolo hanno gli exit code in Job/Pod? Un task e considerato riuscito se termina con 0; in caso di
errore (codice non zero) il Job puo ritentare fino al limite configurato.

10. Cosa succede se una liveness probe fallisce ripetutamente? Il kubelet riavvia il container; per app
lente all'avvio e meglio proteggersi con startup probe o delay iniziale.

11. Perche ConfigMap e Secret sono legati ai namespace? Perche sono risorse namespaced: esistono
solo nel namespace dove le crei, quindi puoi avere stessi nomi in namespace diversi.

12. Quali campi minimi devo ricordare per un CronJob? schedule (intervallo di esecuzione) e
jobTemplate (definizione del Job da lanciare).

Takeaway Part 2 per l'esame

1. PV offre storage, PVC lo richiede; il Pod lo monta.


2. Namespace = isolamento logico dei workload nello stesso cluster.
3. ConfigMap per config non sensibile, Secret per credenziali.
4. Probes ben configurate migliorano affidabilita e disponibilita.
5. Job/CronJob sono lo strumento giusto per workload batch e schedulati.
6. Readiness gestisce il traffico, Liveness i restart, Startup protegge gli avvii lenti.
7. Exit code e retry policy (backoffLimit) sono centrali nel comportamento dei Job.

49 / 62
[Link] 2026-05-07

8. Kubernetes – Part 3
Riassunto completo

Labels e Selectors

Le labels sono coppie chiave-valore nei metadata degli oggetti (es. Pod), utili per organizzarli e
raggrupparli logicamente.
Non devono essere uniche: piu oggetti possono avere le stesse labels.
I selectors servono a selezionare insiemi di oggetti tramite labels.
Tipi principali:
equality-based: ==, !=
set-based: in, notin, exists
Se un selector ha piu condizioni separate da virgola, valgono tutte (AND logico).

Oggetti core per workload cloud-native

Nella pratica di orchestrazione si usano soprattutto:


ReplicaSet
Deployment
StatefulSet
HorizontalPodAutoscaler (HPA)
Service
Ingress

ReplicaSet

Supervisiona Pod long-running e mantiene il numero desiderato di repliche.


50 / 62
[Link] 2026-05-07

Decide quali Pod controllare tramite labels + selector.


Operazioni tipiche:
creazione: kubectl apply -f ...
scaling: update manifest o kubectl scale rs <name> --replicas=<n>
rimozione: kubectl delete -f ...
E un oggetto a basso livello: in genere e preferibile usare Deployment/StatefulSet.

Deployment (stateless)

Oggetto consigliato per servizi stateless.


Mantiene le repliche e gestisce aggiornamenti dichiarativi.
Funzionalita chiave:
rolling update (default)
gestione rollout problematici
rollback versionato
Internamente usa ReplicaSet: durante update puo gestire vecchio e nuovo ReplicaSet in parallelo per
transizione graduale.

StatefulSet (stateful)

Versione stateful del Deployment per workload con identita/stato persistente (es. database).
Quando un Pod stateful cade, va recuperato in modo coerente col suo stato.
Principio pratico: evitare naked Pods (Pod non gestiti da controller), perche non garantiscono resilienza
in caso di failure del nodo.

HPA (HorizontalPodAutoscaler)

Automatizza scale up/down di Deployment o StatefulSet in base a metriche (es. CPU, memoria).
Flusso logico:
1. monitori metriche,
2. definisci target/soglie,
3. HPA regola il numero di repliche.
Campi chiave del manifest:
scaleTargetRef
minReplicas
maxReplicas
metrics
L'HPA controller rivaluta periodicamente (tipicamente ogni ~15s).

Accesso ai Pod: Service e bilanciamento

Con piu Pod dietro la stessa app, serve un punto di accesso stabile e bilanciato.
In Kubernetes questo e il Service: set logico di Pod + policy di accesso.
Service discovery: IP e DNS stabili lato Service, mentre i Pod possono cambiare.
Il traffico viene inoltrato ai Pod selezionati (kube-proxy; default round-robin, configurabile anche con
IPVS).

Tipi di Service
51 / 62
[Link] 2026-05-07

ClusterIP (default): accesso interno al cluster.


NodePort: espone una porta su ogni nodo (<NodeIP>:<NodePort>), tipicamente range 30000-32767.
LoadBalancer: crea un LB esterno con IP pubblico.
ExternalName: mapping DNS CNAME verso nome esterno (senza proxying diretto di Pod).

Ingress

Se devi esporre piu servizi su Internet, usare un LB per ogni Service e costoso/rigido.
Ingress fornisce regole L7 (tipicamente HTTP/HTTPS) per routing host/path verso servizi interni.
Componenti:
oggetto Ingress con regole e possibile defaultBackend
Ingress Controller (Nginx, Contour, Istio, ecc.) che implementa realmente il routing.
Vantaggi: un solo endpoint esterno, routing avanzato, integrazione TLS/certificati.

Helm Package Manager

Helm e il package manager di Kubernetes.


Un pacchetto Helm e un Chart (manifest + configurazioni).
Vantaggi:
deploy semplificato di stack complessi (es. Redis cluster)
riuso e standardizzazione
configurazione per ambienti multipli (dev/staging/prod) tramite [Link]
Struttura tipica chart:
[Link] (metadata)
[Link] (valori)
templates/ (manifest template)
charts/ (dipendenze)
Le template usano Go template ({{ ... }}) e oggetti built-in come Release, Values, Files,
Capabilities, Template.

Kubernetes in locale

Per sviluppo locale conviene usare cluster leggeri single-node:


Minikube
MicroK8s
Minikube aiuta a testare rapidamente Kubernetes su laptop e integra anche la Kubernetes Dashboard.

Domande demo Kubernetes Part 3 - risposta guidata

1. A cosa servono labels e selectors? A identificare e selezionare gruppi di oggetti in modo flessibile
(base di grouping/routing/scaling in K8s).

2. Perche non usare ReplicaSet direttamente in produzione applicativa? Perche


Deployment/StatefulSet aggiungono update strategy, rollback e gestione di livello piu alto.

3. Quando scelgo Deployment e quando StatefulSet? Deployment per stateless; StatefulSet per
workload stateful che richiedono identita/stato coerente.

52 / 62
[Link] 2026-05-07

4. Perche evitare naked Pods? Senza controller non hai garanzie forti di ripristino/rischedulazione in caso
di failure.

5. Come scala automaticamente Kubernetes rispetto al carico? Con HPA, che osserva metriche e adatta
il numero di repliche entro i limiti min/max.

6. Perche serve un Service davanti ai Pod? Per avere endpoint stabile, discovery DNS e bilanciamento
verso Pod che cambiano nel tempo.

7. Quale tipo di Service usare? ClusterIP per interno, NodePort per esposizione semplice, LoadBalancer
per IP pubblico, ExternalName per alias DNS esterno.

8. Come espongo molti servizi HTTP sotto stesso dominio/IP? Con Ingress + controller, usando regole
host/path verso backend diversi.

9. Che problema risolve Helm? Evita gestione manuale di molti manifest: pacchettizza deployment
complessi in chart configurabili.

10. Qual e il setup pratico per sviluppo locale? Minikube/MicroK8s per cluster locale leggero; Dashboard
per osservare risorse e troubleshooting.

Mappa demo Part 3 (slide-by-slide)

Demo 01-02: Play with ReplicaSets.


Demo 02-03: Play with Deployments.
Demo 04: Play with StatefulSets.
Demo 05: Play with HPA.
Demo 06: The LoadBalancer Service.

Takeaway Part 3 per l'esame

1. Labels/selectors sono la base di grouping, targeting e automazione in Kubernetes.


2. ReplicaSet mantiene repliche, ma Deployment/StatefulSet sono i controller raccomandati.
3. HPA automatizza lo scaling orizzontale in base a metriche e soglie.
4. Service disaccoppia client e Pod con IP/DNS stabili e load balancing.
5. Ingress e la soluzione standard per esporre piu servizi HTTP/HTTPS con routing avanzato.
6. Helm accelera deploy e gestione di stack complessi con chart template-driven.
7. Minikube/MicroK8s rendono pratico lo sviluppo Kubernetes in locale.

9. Authentication and Security (dal PDF)


Riassunto completo

Problema iniziale: fiducia e riservatezza

Domande chiave: posso fidarmi del servizio che sto contattando? Il traffico e leggibile in rete?
Con HTTP puro, i dati possono essere intercettati (man-in-the-middle), soprattutto se contengono
informazioni sensibili.

HTTPS e TLS
53 / 62
[Link] 2026-05-07

HTTPS = HTTP sopra canale cifrato TLS (storicamente SSL).


TLS ha due obiettivi principali:
autenticare il server (e opzionalmente anche il client);
garantire confidenzialita e integrita dei dati scambiati.
TLS e un protocollo ibrido:
crittografia asimmetrica per autenticazione e negoziazione segreti;
crittografia simmetrica per il traffico applicativo (piu efficiente).

Crittografia simmetrica e asimmetrica

Simmetrica: stessa chiave per cifrare/decifrare (es. AES, Blowfish, Twofish, Serpent).
Asimmetrica: coppia chiave pubblica/privata (es. RSA, Diffie-Hellman per key exchange).
L'asimmetrica consente scambio sicuro iniziale e firma digitale; la simmetrica gestisce il traffico di
sessione.

Handshake TLS (visione pratica)

Fasi principali:
1. Hello: client e server negoziano versione/cipher suite.
2. Certificate exchange: il server presenta il certificato per dimostrare identita.
3. Key exchange: viene stabilito il segreto condiviso usato dalla cifratura simmetrica.
Dopo handshake, richieste/risposte HTTP viaggiano cifrate.

Certificati e Certificate Authorities (CA)

Un certificato contiene identita proprietario, dominio, chiave pubblica, firma digitale e validita
temporale.
La fiducia dipende dalla catena CA: i client fidano CA note (es. Let's Encrypt, DigiCert, Comodo,
GoDaddy).
Self-signed:
utili per test/lab;
non adatti a connessioni pubbliche sensibili senza un modello di trust controllato.

HTTPS con load balancer

Se c'e un LB davanti ai backend, devi scegliere dove terminare TLS:


SSL/TLS Termination: TLS finisce al LB, backend in chiaro.
SSL/TLS Pass-Through: TLS arriva fino ai backend.
SSL/TLS Bridging: TLS termina al LB e viene ristabilito verso backend.
Trade-off tipico:
termination = piu semplice e ispezionabile;
pass-through = meno manipolazione ma meno controllo L7 al LB;
bridging = piu sicurezza end-to-end, ma piu costo CPU e complessita.

OAuth 2.0: autorizzazione delegata

OAuth2 e un framework di autorizzazione (non un protocollo di autenticazione puro).


Permette a un client di accedere a risorse utente senza conoscere username/password utente.

54 / 62
[Link] 2026-05-07

Ruoli OAuth:
Resource Owner (utente)
Client (applicazione)
Authorization Server (emette token)
Resource Server (API protetta)

Flusso OAuth2 astratto

1. Il client chiede autorizzazione all'utente.


2. L'utente concede un authorization grant.
3. Il client scambia il grant con un access token presso l'authorization server.
4. Il client usa l'access token per chiamare il resource server.
5. Se token valido, il resource server restituisce la risorsa.

Grant types principali

Authorization Code (consigliato): adatto a web/mobile; per SPA/public client usare PKCE.
Client Credentials: comunicazione service-to-service (nessun utente umano).
Device Code: dispositivi con input limitato (TV, console).
Implicit: legacy, non raccomandato.
Password: legacy/discontinuato in OAuth 2.1.

Access token, refresh token e lifetime

Access token: usato per chiamare API, limitato da scope/tempo.


Refresh token: usato per ottenere nuovi access token senza nuova autenticazione utente.
Strategie comuni lifetime:
access token breve + refresh token lungo (equilibrio UX/sicurezza);
access token breve senza refresh (piu sicurezza, meno accesso offline);

55 / 62
[Link] 2026-05-07

token non scadenti (piu semplice, ma revoca/gestione rischio piu critica).

OAuth2 con Spring Security

Spring Security supporta OAuth2 nativamente (provider/consumer), senza dipendenza legacy Spring
Security OAuth.
Riferimento pratico: configurare client/resource server seguendo i moduli OAuth2 moderni del
framework.

JWT (JSON Web Token)

JWT e un formato standard compatto per trasmettere informazioni (claims) in modo verificabile tra
parti.
I token JWT possono essere firmati:
con segreto condiviso (es. HMAC);
con coppia chiave pubblica/privata (es. RSA/ECDSA).
Struttura compatta: [Link].
header: tipo token (JWT) + algoritmo (alg).
payload: claims (registered, public, private).
signature: firma digitale per verificare integrita e origine.
Importante: payload/header non sono cifrati di default (solo codifica Base64Url), quindi non vanno usati
per dati segreti se non con cifratura.

JWT: uso pratico e relazione con OAuth2

Dopo login, il client invia il token nelle richieste protette via header:
Authorization: Bearer <token>
JWT non sostituisce OAuth2: OAuth2 definisce il protocollo di autorizzazione, JWT e un possibile
formato del token (es. access token).

JWT con Spring Boot (idea operativa)

Flusso base mostrato nelle slide:

56 / 62
[Link] 2026-05-07

1. endpoint /token che valida credenziali e genera JWT;


2. token firmato (es. HS256) con claims e scadenza;
3. filtro custom che legge Authorization, verifica firma/scadenza e estrae claims;
4. endpoint protetti accessibili solo con token valido.
Dipendenza tipica mostrata: libreria jjwt.

Keycloak (IAM)

Keycloak e una piattaforma open-source di Identity and Access Management (IAM) per aggiungere
autenticazione/autorizzazione alle applicazioni.
Punti chiave:
SSO/SLO per applicazioni browser.
Identity brokering (OIDC/SAML) e social login.
User federation con LDAP/Active Directory.
Console admin e console account utente (profilo, password, 2FA, ecc.).

Keycloak: concetti principali

Users: identita con attributi.


Roles: categorie/permessi (admin, user, manager...).
Realms: domini isolati di utenti, ruoli e client.
master realm per amministrazione globale.
altri realm per applicazioni/tenant specifici.
Clients: applicazioni/servizi che delegano autenticazione a Keycloak.
Access token: token da includere nelle chiamate HTTP verso servizi protetti.

Keycloak e Spring Boot

Gli adapter Spring Boot dedicati di Keycloak sono stati deprecati.


Approccio raccomandato: usare Spring Security OAuth2/OpenID Connect standard per integrazione
moderna.

Domande auth_security - risposta guidata

1. Perche HTTP non basta in ambienti reali? Perche il traffico in chiaro puo essere
intercettato/modificato; con dati sensibili e un rischio diretto.

2. Cosa garantisce TLS in HTTPS? Identita del server, confidenzialita del traffico e integrita dei messaggi.

3. Perche TLS usa sia asimmetrica che simmetrica? L'asimmetrica serve per trust e key exchange iniziale;
la simmetrica per performance sul traffico continuo.

4. Quando evitare certificati self-signed? In produzione pubblica: senza catena di fiducia robusta non
garantiscono identita verificabile lato client.

5. Termination vs Pass-Through sul load balancer: come scelgo? Termination se vuoi controllo L7
semplice; pass-through se vuoi TLS fino al backend; bridging se vuoi entrambe le cose con costo
maggiore.

57 / 62
[Link] 2026-05-07

6. OAuth2 serve per autenticazione o autorizzazione? Principalmente autorizzazione delegata:


permette accesso limitato alle API senza condividere credenziali utente.

7. Qual e il grant type standard oggi per app web/mobile? Authorization Code, con PKCE quando il
client non puo custodire segreti in modo sicuro.

8. Quando usare Client Credentials? Per chiamate machine-to-machine dove il client agisce per se
stesso.

9. A cosa serve il refresh token? A rinnovare access token scaduti senza rifare login completo dell'utente.

10. Cosa cambia in Spring moderno per OAuth2? Il supporto e integrato in Spring Security corrente; non
serve la vecchia libreria dedicata legacy.

11. JWT e OAuth2 sono la stessa cosa? No: OAuth2 e un framework/protocollo di autorizzazione; JWT e
un formato di token che puo essere usato dentro OAuth2.

12. Quali sono le 3 parti di un JWT? Header, payload, signature ([Link]), con firma
usata per verificare integrita/autenticita.

13. Posso mettere password o segreti nel payload JWT? No, non in chiaro: payload/header sono leggibili
se non cifrati; usare solo claims necessari e non sensibili.

14. Che ruolo ha Keycloak in un'architettura cloud-native? Centralizza IAM: login, token, ruoli,
federazione identita e SSO per piu applicazioni.

15. Perche i realm di Keycloak sono importanti? Perche isolano utenti/ruoli/client tra contesti diversi
(ambienti, tenant, domini applicativi).

Takeaway Auth_Security per l'esame

1. HTTPS/TLS risolve trust e cifratura del canale, non solo privacy ma anche autenticita endpoint.
2. Certificati + CA sono il cuore del modello di fiducia su Internet.
3. In presenza di load balancer, la scelta del punto di terminazione TLS impatta sicurezza, costo e
operativita.
4. OAuth2 abilita delega sicura dell'accesso alle risorse tramite token e scope.
5. Authorization Code (+ PKCE) e il flusso di riferimento moderno per client con utente.
6. Access token e refresh token vanno progettati insieme con lifetime coerente al rischio.
7. JWT e un formato token firmato: utile per claims e propagazione identita, ma non e un protocollo di
auth.
8. Header/payload JWT non vanno trattati come spazio sicuro per segreti.
9. Keycloak offre IAM completo (SSO, federation, ruoli, realm, client).
10. In Spring moderno, integrazione consigliata tramite OAuth2/OIDC standard di Spring Security.

10. Microservices (dal PDF)


Riassunto completo

Cosa sono i microservices

58 / 62
[Link] 2026-05-07

L'architettura a microservizi sviluppa un sistema come insieme di servizi piccoli, ognuno in un proprio
processo.
I servizi comunicano con meccanismi leggeri (tipicamente HTTP/REST, ma anche messaggistica
asincrona).
Ogni servizio e costruito attorno a una capability di business e deve essere deployabile in modo
indipendente.
E possibile usare stack tecnologici diversi tra servizi (linguaggi, database, framework), con governance
centralizzata minima.

Perche sono emersi

I microservizi sono visti come evoluzione pratica della SOA in contesti web/mobile/IoT moderni.
La loro diffusione e collegata alla necessita di rilasciare software piu velocemente e in modo piu
affidabile.
La crescita parallela di DevOps, CI/CD, containerizzazione e API Gateway ha reso questo modello
operativo su larga scala.

Monolite: cosa funziona e cosa no

Vantaggi del monolite:


sviluppo iniziale semplice (tooling/IDE ottimizzati);
deploy semplice (artifact unico);
scaling orizzontale base duplicando l'app dietro un load balancer.
Limiti principali quando sistema e team crescono:
codebase grande e difficile da comprendere;
startup/deploy lenti;
un piccolo cambiamento richiede redeploy completo;
impossibilita di scalare componenti in modo indipendente;
coupling forte su un unico stack tecnologico.

Benefici chiave dei microservices

Technology heterogeneity: scegliere tecnologia adatta al singolo problema.


Resilience: guasti isolabili per servizio, con degrado controllato invece di blocco totale.
Scaling mirato: si scala solo il servizio che ne ha bisogno.
Ease of deployment: rilascio indipendente di un singolo servizio.
Organizational alignment: team piccoli, cross-funzionali e piu autonomi.
Composability: riuso funzionalita via servizi.
Replaceability: servizio piccolo piu semplice da riscrivere, sostituire o eliminare.

Drawbacks reali da gestire

Aumento della complessita distribuita (rete, latenza, fault handling, coordinamento).


Testing/debugging piu difficile e maggiore bisogno di osservabilita.
Complessita operativa di deployment e gestione di molti servizi.
Overhead infrastrutturale (processi/JVM/istanze multiple, consumo memoria).
Gestione dati piu complessa: spesso niente strong consistency globale, si adotta eventual consistency.

59 / 62
[Link] 2026-05-07

Quando ha senso adottarli

Principio guida del corso: non scegliere microservices se il monolite e ancora gestibile.
Valuta microservices quando la complessita nasce da:
team grandi o distribuiti;
multi-tenancy;
molte modalita di interazione utente;
necessita che funzioni di business evolvano indipendentemente;
esigenze di scaling differenziato;
monolite diventato troppo grande per modifiche/deploy rapidi.

Principi di progettazione: loose coupling e high cohesion

Loose coupling: i servizi devono cambiare/deployare in autonomia, esponendo solo le informazioni


necessarie.
High cohesion: comportamenti correlati nello stesso servizio; comportamenti non correlati separati.
Obiettivo pratico: ridurre impatti laterali e velocizzare rilascio del cambiamento.

Comunicazione inter-service

Possibile combinare stili sincroni e asincroni.


Dimensioni principali:
one-to-one vs one-to-many;
synchronous vs asynchronous.
Tecnologie menzionate:
HTTP/REST per richieste sincrone;
AMQP/message queue (es. RabbitMQ, ActiveMQ, SQS, RocketMQ);
pub/sub (es. Kafka, SNS, Google Pub/Sub, Pulsar).

Gestione dei failure parziali

60 / 62
[Link] 2026-05-07

Pattern operativi fondamentali:


timeout sempre espliciti (mai attesa indefinita);
limite alle richieste outstanding verso servizi dipendenti;
circuit breaker basato su failure rate;
fallback (cache/default response) quando dipendenze non disponibili.

Dati e migrazioni in architettura a microservizi

Ogni servizio tende ad avere il proprio database (polyglot persistence possibile).


Le migrazioni schema devono essere versionate insieme al codice e integrate nella pipeline di deploy.
Tool tipici: Flyway/Liquibase.
Con rolling update Kubernetes, migrazioni devono essere backward-compatible durante coesistenza
vecchia+nuova versione.
Operazioni non backward-compatible (rename/drop/type change) richiedono processo multi-step.

Esempio: rename colonna senza downtime (4 step)

1. Aggiungere nuova colonna con stesso tipo della vecchia.


2. Copiare dati a shard + trigger per sincronizzare vecchia e nuova colonna.
3. Eseguire rolling update delle istanze applicative.
4. Rimuovere vecchia colonna e trigger dopo fase di monitoraggio/quarantena.

Migrazione da monolite a microservices

Cercare logica business separabile e moduli naturalmente isolati.


Identificare parti con profili di scaling/memoria diversi.
Prima ridurre dipendenze innaturali nel monolite con refactoring interno, poi estrarre servizi.

Ecosistema e framework citati nel corso

Reactive systems / reactive microservices: sistemi responsive, resilient, elastic e message-driven.


Spring Cloud: pattern distribuiti pronti (service discovery, config, circuit breaker, routing, ecc.).
Kubernetes: supporto nativo a service discovery, load balancing, health probes, config esterna.
Spring Native/GraalVM: startup rapido e riduzione memoria utili per workload microservice.

Domande Microservices - risposta guidata

1. Definizione sintetica di microservice? Servizio piccolo, autonomo, focalizzato su una capability di


business, deployabile indipendentemente e comunicante via protocolli leggeri.

2. Perche i microservices sono associati a DevOps e CI/CD? Perche il valore del modello emerge
quando puoi rilasciare spesso e in modo automatizzato singoli servizi.

3. Qual e il principale limite del monolite in fase di crescita? Ogni modifica richiede impatti ampi
(build/test/deploy), rallentando team e rilascio.

4. In che senso i microservices migliorano la resilienza? Isolano i guasti: il fallimento di un servizio puo
degradare una sola funzione, non l'intero sistema.

61 / 62
[Link] 2026-05-07

5. Quando NON dovresti usare microservices? Quando il monolite e ancora gestibile e la complessita
distribuita supererebbe i benefici.

6. Loose coupling e high cohesion cosa significano in pratica? Servizi indipendenti nelle dipendenze
esterne e internamente focalizzati su responsabilita coerenti.

7. Sincrono o asincrono nella comunicazione tra servizi? Dipende dal caso d'uso: sincrono per
immediatezza/semplicita, asincrono per disaccoppiamento, resilienza e throughput.

8. Quali pattern usare contro failure parziali? Timeout, limiti di richieste concorrenti, circuit breaker e
fallback.

9. Perche ogni microservizio tende ad avere il proprio DB? Per ridurre accoppiamento e permettere
evoluzione indipendente del dominio dati del servizio.

10. Perche le migrazioni DB sono critiche con rolling update? Perche vecchia e nuova versione
convivono: lo schema deve restare compatibile durante il rollout.

11. Perche un rename diretto di colonna e rischioso in produzione? Perche rompe compatibilita tra
versioni applicative diverse ancora in esecuzione.

12. Quando usare message queue/pub-sub invece di REST puro? Quando vuoi disaccoppiare tempi di
risposta, assorbire picchi e gestire eventi asincroni.

13. Che contributo da Kubernetes ai microservices? Fornisce primitive operative standard: service
discovery, bilanciamento, health check, config management e rollout.

14. Qual e il ruolo di Spring Cloud in questo contesto? Riduce boilerplate offrendo implementazioni
pronte di pattern distribuiti comuni.

15. Come si inizia una migrazione da monolite? Con refactoring interno per isolare confini di dominio,
poi estrazione incrementale dei servizi piu adatti.

Takeaway Microservices per l'esame

1. Microservices non sono un fine: sono una risposta a complessita tecnica/organizzativa specifica.
2. Il trade-off fondamentale e autonomia dei servizi vs complessita distribuita.
3. Le decisioni vanno prese su confini di business (bounded context), non solo su criteri tecnici.
4. Osservabilita, resilienza e automazione deploy sono prerequisiti operativi, non opzionali.
5. Comunicazione inter-service richiede scelta consapevole tra sync e async.
6. La gestione dati e il punto piu delicato: eventual consistency e migrazioni backward-compatible sono
centrali.
7. Rolling update impone strategie di schema evolution multi-step.
8. Kubernetes e Spring Cloud accelerano l'adozione ma non eliminano la complessita architetturale.
9. Team topology e architettura devono essere allineati per ottenere vero beneficio.
10. Regola pratica: partire monolitici quando possibile, passare a microservices quando la complessita lo
richiede davvero.

62 / 62

Potrebbero piacerti anche