Openshift: cos'è e perché piace ai Dev, agli Ops e al business
CLOUD & DEVOPS
Openshift: cos'è e perché piace ai Dev, agli Ops e al business
event 16/07/2018

In un precedente articolo ho avuto modo di parlare dei vantaggi dell'elasticità del cloud e dei risultati che si possono ottenere grazie al passaggio da server mutabili (VM) a potenzialmente immutabili (container).
Per raggiungere tali risultati è necessario gestire i container così come viene gestito il codice sorgente: bisogna introdurre un workflow di CI/CD che coinvolga anche i container.
La piattaforma Red Hat Openshift ha un vantaggio fondamentale rispetto ad analoghi prodotti che servono a gestire i container (orchestratori di container): permette di definire un workflow di CI/CD completo, che parte dal codice sorgente dell'applicazione e dal codice che descrive le immagini per giungere al deploy delle applicazioni containerizzate.
Naturalmente Openshift è in primo luogo un eccellente orchestratore di container. Esso è basato su Kubernetes, un prodotto open source creato da Google a partire da una lunga esperienza di utilizzo e gestione di container in ambienti di produzione ad alte prestazioni.
L'utilità di un orchestratore di container
Un orchestratore di container è indispensabile per gestire sistemi distribuiti che fanno uso di un gran numero di container:
- esso permette di gestire applicazioni moderne, strutturate a micro-servizi;
- gestire un gran numero di micro-servizi in un cluster di server è molto complicato senza un orchestratore di container: è necessario risolvere problemi di deployment combinato dei container, gestire il networking multi-host dei container, il service discovery, la gestione dei volumi persistenti in modo distribuito e così via;
- Openshift, come Kubernetes, permette di gestire in modo semplice lo scaling dei servizi e il load balancing tra le repliche di uno stesso servizio. Questa funzionalità rende semplice ottenere lo scaling selettivo delle singole componenti di un'applicazione a micro-servizi.
Le caratteristiche di Openshift
Per installare Openshift è sufficiente avere un cluster di macchine con sistema operativo RHEL.
Non ha importanza come siano fatti i server: possono essere server fisici, VM oppure macchine su cloud pubblici e privati. Openshift tratta questo cluster di server come pure risorse di calcolo e di storage e crea su di esso uno strato di astrazione nel quale vivono le applicazioni containerizzate.
Openshift è esso stesso un sistema distribuito fatto da diversi componenti. Ciascun componente del sistema è installabile in alta affidabilità, in modo da non avere punti deboli (nessun "single point of failure").
Openshift è costruito a partire da Kubernetes ma sfrutta diversi altri progetti e tecnologie open source (come Source 2 Image, la tecnologia che permette di passare dal codice sorgente di un'applicazione all'applicazione containerizzata, o Jenkins, un popolarissimo server di CI/CD). Kubernetes a sua volta, è un aggregato di prodotti open source sostenuti da una community di sviluppatori che ha pochi uguali al mondo per numerosità e livello di partecipazione.
Openshift è pensato in modo da essere facile da usare:
- mette a disposizione diverse interfacce utente (web-based oppure in linea di comando, per permettere una migliore automazione), delle API che danno la possibilità di gestire ogni aspetto della piattaforma e una serie di runtime per facilitare la creazione di applicazioni containerizzate.
- mette a disposizione un ricco catalogo di linguaggi e di server (es. application server, broker di code e altri prodotti middleware) per costruire sistemi distribuiti complessi e applicazioni a micro-servizi in modo semplificato.
- è inoltre pensato per assecondare la collaborazione tra utenti minimizzando le interferenze indesiderate. La piattaforma è multitenancy e dotata di un sistema articolato di gestione degli utenti, dei ruoli e dei permessi. L'accesso alle risorse può essere controllato a un livello di granularità estremamente fine e l'utilizzo di qualsiasi risorsa può essere sottoposto a limitazioni.
Openshift: per una più stretta collaborazione tra sviluppatori e sistemisti
Openshift costituisce quindi la piattaforma ideale per ottimizzare la collaborazione tra sviluppatori e sistemisti. Openshift permette agli sviluppatori di approvvigionarsi in modo autonomo di tutti gli strumenti necessari per costruire applicazioni e workflow di build e deploy sofisticati a piacimento; d'altro canto, i sistemisti hanno il pieno controllo della piattaforma, dell'utilizzo che viene fatto delle risorse e, grazie alle immagini e ai container, dell'ambiente di esecuzione delle applicazioni, potendo tra l'altro accedere in modo immediato alle eventuali fix di sicurezza pubblicate da Red Hat e applicarle in modo istantaneo ai container che girano sulla piattaforma.
Red Hat OpenShift è una piattaforma PaaS per applicazioni cloud che automatizza l’hosting, la configurazione, l’implementazione e l’amministrazione degli stack di applicazioni in un ambiente cloud flessibile.
Per approfondire questo argomento e scoprire come OpenShift può aiutarti a portare al minimo il time-to-market delle tue applicazioni
rocket_launch Guarda il webinar!Guarda il webinar!
explore Vai al videoFailed to "?eval" string with this error: ---begin-message--- Syntax error in ?eval-ed string in line 1, column 702: Lexical error: encountered "u" (117), after "\"Extra\\". ---end-message--- The failing expression: ==> entitiesListJson?eval [in template "20097#20123#43230" at line 59, column 29] ---- FTL stack trace ("~" means nesting-related): - Failed at: #assign entities = entitiesListJson?eval [in template "20097#20123#43230" at line 59, column 9] ----
1<#-- Articoli in evidenza ADT -->
2<#assign portletBackground = "bg-red-white" />
3<#list portletPreferences?keys as key>
4 <#if key=="portletBackground">
5 <#assign portletBackground=portletPreferences[key]?first />
6 </#if>
7</#list>
8
9<#assign assetCategoryPropertyLocalService = serviceLocator.findService("com.liferay.asset.category.property.service.AssetCategoryPropertyLocalService") />
10<#assign categoryService = serviceLocator.findService("it.extrared.redweb.commons.service.CategoryService") />
11<#assign assetEntryLocalService=serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
12<#assign dlFileEntryService = serviceLocator.findService('com.liferay.document.library.kernel.service.DLFileEntryService') />
13<#assign otherArticles = languageUtil.get(locale, "other-articles") />
14<#assign readMore = languageUtil.get(locale, "read-all") />
15
16<#assign redSimilarJournalArticle = serviceLocator.findService("it.extrared.redweb.commons.service.SimilarJournalArticle") />
17<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
18<#assign dlAppServiceUtil = serviceLocator.findService("com.liferay.document.library.kernel.service.DLAppService")/>
19
20<#assign article = "" />
21<#assign urlTitle = "" />
22
23<#assign dirtyUrlTitle = themeDisplay.getURLCurrent() />
24<#assign curPage = 1 />
25
26<#if dirtyUrlTitle?contains("redirect")>
27 <#assign namespace = "_" + paramUtil.getString(request, "p_p_id") />
28 <#assign currentUrl = "_" + paramUtil.getString(request, namespace + "_redirect") />
29 <#assign urlTitle = currentUrl?split("/")?last />
30 <#assign curPage = paramUtil.getString(request, namespace + "_cur")/>
31<#elseif dirtyUrlTitle?contains("?wkrh___tabs1=properties")>
32 <#assign last = themeDisplay.getURLCurrent()?split("/")?last />
33 <#assign urlTitle = last?substring(0, last?index_of('?wkrh___tabs1=properties')) />
34<#elseif dirtyUrlTitle?contains("?")>
35 <#assign last = themeDisplay.getURLCurrent()?split("/")?last />
36 <#assign urlTitle = last?substring(0, last?index_of('?')) />
37<#else>
38 <#assign urlTitle = themeDisplay.getURLCurrent()?split("/")?last />
39</#if>
40
41
42<#assign logfactory = staticUtil["com.liferay.portal.kernel.log.LogFactoryUtil"] />
43<#assign log = logfactory.getLog("FreemarkerLog") />
44${log.info("urlTitle: " + urlTitle)}
45
46<#attempt>
47 <#assign article = journalArticleLocalService.getArticleByUrlTitle(groupId, urlTitle) />
48<#recover>
49</#attempt>
50
51<#assign entitiesListJson = "" />
52
53<#if article?? && article?has_content>
54 <#assign entitiesListJson = redSimilarJournalArticle.getSimilarJournalArticlesWithConfig(portletPreferences, article.articleId, groupId, false, curPage?number) />
55</#if>
56
57
58<#if entitiesListJson?? && entitiesListJson?has_content>
59 <#assign entities = entitiesListJson?eval />
60</#if>
61
62<#assign noResult = languageUtil.get(locale, "no-result") />
63
64<#if entities?has_content && entities?size gt 0>
65 <section class="container-fluid bg5percent">
66 <div class="swiper container ">
67 <p class="mb-5 text-muted text-uppercase">${otherArticles}</p>
68 <div class="swiper-wrapper align-items-center pt-lg-5 mb-lg-5">
69 <#list entities?keys as k>
70 <#assign entitiesGroup=entities[k] />
71 <#if entitiesGroup?size gt 0>
72 <#list entitiesGroup as array>
73 <div class="swiper-slide">
74 <#assign urlImage = "" />
75 <#assign altImage = "" />
76 <#if array["image"]?? && array["image"]?has_content>
77 <#assign docVal=array["image"]?eval />
78 <#if docVal.url?? && docVal.url?has_content>
79 <#assign urlImage = docVal.url />
80 </#if>
81 <#assign fileEntryId = docVal.fileEntryId />
82 </#if>
83
84 <#if docVal.title?? && docVal.title?has_content>
85 <#assign altImage = docVal.title />
86 </#if>
87
88 <#assign titolo = array["articleTitle"] />
89 <#assign categories = array["categoriesString"] />
90 <#assign displayPage = array["displayPage"] />
91 <#assign assetEntryId = array["assetEntryId"] />
92 <#assign assetEntry = assetEntryLocalService.getEntry(assetEntryId) />
93 <#assign categoriesList = assetEntry.getCategories() />
94
95 <div class="col-lg-9 col-9 col-sm-9 p-0">
96 <@adaptive_media_image["img"] fileVersion=dlAppServiceUtil.getFileEntry(fileEntryId?number).getFileVersion() class="mb-4" width="100%" height="auto" alt="${altImage}"/>
97 <#--
98 <img width="100%" class="mb-4" height="auto" src="${urlImage}" alt="${altImage}" title="${titolo}">
99 -->
100 </div>
101 <div class="card-body pt-2">
102 <#if categoriesList?? && categoriesList?has_content>
103 <div class="card-subtitle text-muted">
104 <#assign categoriesString = "" />
105 <#list categoriesList as c>
106 <#assign hasProperty = categoryService.hasCategoryProperty(c.getCategoryId(), "type") />
107 <#if !hasProperty>
108 <#if !categoriesString?has_content>
109 <#assign categoriesString = c.getTitle(locale)?upper_case />
110 <#else>
111 <#assign categoriesString = categoriesString + ", " + c.getTitle(locale)?upper_case />
112 </#if>
113 </#if>
114 <#--
115 <#attempt>
116 <#assign typeProperty = assetCategoryPropertyLocalService.fetchCategoryProperty(c.categoryId?long, "type") />
117 <#recover>
118 <#if !categoriesString?has_content>
119 <#assign categoriesString = c.getTitle(locale)?upper_case />
120 <#else>
121 <#assign categoriesString = categoriesString + ", " + c.getTitle(locale)?upper_case />
122 </#if>
123 </#attempt>
124 -->
125 </#list>
126
127 ${categoriesString}
128 </div>
129 </#if>
130 <a href="${displayPage}" target="_self" title="${titolo}">
131 <h3 class="m-0">${titolo}</h3>
132 </a>
133 </div>
134 </div>
135 </#list>
136 <#else>
137 <div class="container">
138 <h2 class="m-0">${noResult}</h2>
139 </div>
140 </#if>
141 </#list>
142 </div>
143 <a data-aos="fade-right" class="pt-5 align-middle" style="display: block" href="/blog">
144 <i class="align-middle me-2 material-icons-outlined">explore</i>
145 <span class="align-middle">${readMore?capitalize}</span>
146 </a>
147 </div>
148 </section>
149</#if>