CLOUD & DEVOPS

Openshift: cos'è e perché piace ai Dev, agli Ops e al business

event 16/07/2018

Openshift: cos'è e perché piace ai Dev, agli Ops e al business

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

Openshift | Platform as a Service

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 video
Si è verificato un errore nell'elaborarazione del modello.
Failed 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>