Probabilmente, non è un segreto per nessuno che l'anno scorso sia stato per Apache Hadoop un anno di grandi cambiamenti. Lo scorso anno, c'è stata la fusione tra Cloudera e Hortonworks (di fatto, l'acquisizione del secondo), e Mapr, a causa di gravi problemi finanziari, è stata venduta a Hewlett Packard. E se qualche anno fa, nel caso di installazioni on-premises, la scelta era tra Cloudera e Hortonworks, oggi, purtroppo, quella scelta non ci è più rimasta. Un'altra sorpresa è stata il fatto che Cloudera ha annunciato a febbraio di quest'anno la cessazione della distribuzione di build binarie del proprio pacchetto nel repository pubblico, e ora sono disponibili solo tramite abbonamento a pagamento. Certo, è ancora possibile scaricare le ultime versioni di CDH e HDP rilasciate entro la fine del 2019, e si prevede supporto per esse per uno o due anni. Ma cosa fare dopo? Per chi ha già pagato un abbonamento, nulla è cambiato. E per chi non vuole passare alla versione a pagamento del pacchetto, ma desidera comunque avere accesso a versioni aggiornate dei componenti del cluster e a patch e aggiornamenti vari, abbiamo preparato questo articolo. Esamineremo le possibili opzioni per affrontare la situazione attuale.
L'articolo è più un riepilogo. Non ci sarà un confronto tra i pacchetti e un'analisi dettagliata, né ricette per la loro installazione e configurazione. E cosa c'è di presente? Parleremo brevemente di un pacchetto come Arenadata Hadoop, che merita la nostra attenzione per la sua accessibilità, cosa piuttosto rara al giorno d'oggi. Poi affronteremo Vanilla Hadoop, principalmente su come si può 'preparare' con Apache Bigtop. Pronti? Allora benvenuti sotto.
Arenadata Hadoop

È un pacchetto completamente nuovo e, per ora, poco conosciuto, sviluppato in patria. Sfortunatamente, al momento su Habr ci sono solo .
Maggiore informazione può essere trovata sul sito ufficiale del progetto. Le ultime versioni del pacchetto sono basate su Hadoop 3.1.2 per la versione 3 e 2.8.5 per la versione 2.
Le informazioni sulla roadmap possono essere trovate .

Interfaccia di Arenadata Cluster Manager
Il prodotto principale di Arenadata è , che viene utilizzato per l'installazione, la configurazione e il monitoraggio di diverse soluzioni software dell'azienda. ADCM è distribuito gratuitamente e la sua funzionalità viene ampliata tramite l'aggiunta di bundle, che consistono in un insieme di ansible-playbooks. I bundle si dividono in due tipi: enterprise e community. Gli ultimi sono disponibili per il download gratuito dal sito Arenadata. C'è anche la possibilità di sviluppare il proprio bundle e collegarlo ad ADCM.
Per il deployment e la gestione di Hadoop 3, viene offerta una versione community del bundle in combinazione con ADCM, mentre per Hadoop 2 c'è solo come alternativa. Per quanto riguarda i repository con i pacchetti, sono aperti al pubblico e possono essere scaricati e installati nel modo consueto per tutti i componenti del cluster. In generale, la distribuzione appare piuttosto interessante. Sono sicuro che ci saranno utenti abituati a soluzioni come Cloudera Manager e Ambari, e che troveranno interessante ADCM. Inoltre, per alcuni, sarà un grande vantaggio che la distribuzione per la sostituzione delle importazioni.
Parlando degli svantaggi, saranno gli stessi di tutte le altre distribuzioni Hadoop. Vale a dire:
- Il cosiddetto "vendor lock-in". Dall'esempio di Cloudera e Hortonworks abbiamo già capito che esiste sempre il rischio di cambiamento della politica aziendale.
- Un significativo ritardo rispetto all'upstream di Apache.
Vanilla Hadoop

Come sapete, Hadoop non è un prodotto monolitico, ma in realtà è un'intera serie di servizi attorno al suo sistema di file distribuito HDFS. Pochi saranno soddisfatti di un solo cluster di file. Alcuni hanno bisogno di Hive, altri di Presto, e poi ci sono HBase e Phoenix, con Spark che viene utilizzato sempre più frequentemente. Per l'orchestrazione e il caricamento dei dati, a volte si utilizzano Oozie, Sqoop e Flume. E se si pone la questione della sicurezza, si pensa subito a Kerberos in combinazione con Ranger.
Le versioni binarie dei componenti Hadoop sono disponibili sui siti di ciascun progetto dell'ecosistema sotto forma di tarball. È possibile scaricarli e avviare l'installazione, ma con una condizione: oltre alla compilazione autonoma dei pacchetti da binari "grezzi", che probabilmente vorrete eseguire, non avrete alcuna certezza sulla compatibilità delle versioni scaricate tra loro. Un'opzione preferibile è la costruzione utilizzando Apache Bigtop. Bigtop consente di compilare dai repository Maven di Apache, eseguire test e creare pacchetti. Ma, ciò che è molto importante per noi, Bigtop compilerà quelle versioni dei componenti che saranno compatibili tra loro. Di questo parleremo più dettagliatamente in seguito.
Apache Bigtop

Apache Bigtop è uno strumento per la costruzione, l'imballaggio e il test di una serie
di progetti open source, come Hadoop e Greenplum, per esempio. Bigtop dispone di numerosi
rilasci. Al momento della redazione dell'articolo, l'ultimo rilascio stabile era la versione 1.4,
mentre nella master c'era la 1.5. In diverse versioni dei rilasci vengono utilizzate versioni diverse
dei componenti. Ad esempio, per la 1.4 i componenti core di Hadoop hanno la versione 2.8.5, mentre nella master
è la 2.10.0. Cambia anche il set di componenti supportati. Qualcosa di obsoleto e
non aggiornato scompare, mentre al suo posto arrivano nuove soluzioni più richieste, e
non necessariamente devono provenire dalla stessa famiglia di Apache.
Inoltre, Bigtop ha numerosi .
Quando abbiamo iniziato a esplorare Bigtop, ciò che ci ha colpito soprattutto è stata la sua modesta, rispetto ad altri progetti Apache, diffusione e notorietà, oltre a una comunità decisamente ridotta. Da ciò ne consegue che le informazioni riguardanti il prodotto sono minime, e la ricerca di soluzioni ai problemi emersi su forum e mailing list potrebbe non portare a nulla. All'inizio, per noi, si è rivelato non semplice completare la costruzione di un'intera distribuzione a causa delle specificità dello strumento stesso, ma di questo parleremo un po' più avanti.
Come anticipazione: a coloro che in passato hanno apprezzato progetti dell'universo Linux come Gentoo e LFS, potrebbe sembrare nostalgicamente gradevole lavorare con questo strumento e ricordare quei "mitici" tempi in cui cercavamo (e talvolta scrivevamo) ebuild e ricompilavamo regolarmente con nuove patch Firefox.
Uno dei grandi vantaggi di Bigtop è l'apertura e la versatilità degli strumenti su cui si basa. Alla sua base ci sono Gradle e Apache Maven. Gradle è piuttosto noto come strumento con cui Google compila Android. È flessibile e, come si suol dire, "provato sul campo". Maven è lo strumento standard per la costruzione di progetti all'interno di Apache, e poiché la maggior parte dei suoi prodotti viene rilasciata tramite Maven, anche in questo caso non si può prescindere da esso. È importante prestare attenzione al POM (project object model) – un file xml "fondamentale" che descrive tutto ciò che è necessario affinché Maven lavori con il tuo progetto, intorno al quale ruota tutto il lavoro. È proprio nel
settore di Maven che sorgono alcuni ostacoli, su cui di solito ci si imbatte quando si inizia a usare Bigtop.
Pratica
Allora, da dove cominciare? Andiamo alla pagina di download e scarichiamo l'ultima versione stabile in forma di archivio. Lì puoi trovare anche gli artefatti binari compilati da Bigtop. A proposito, i gestori di pacchetti più comuni supportano YUM e APT.
In alternativa, puoi scaricare l'ultima versione stabile direttamente da
github:
$ git clone --branch branch-1.4 https://github.com/apache/bigtop.gitClonazione in "bigtop"…
remote: Enumerating objects: 46, done.
remote: Counting objects: 100% (46/46), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 40217 (delta 14), reused 10 (delta 1), pack-reused 40171
Receiving objects: 100% (40217/40217), 43.54 MiB | 1.05 MiB/s, done.
Resolving deltas: 100% (20503/20503), done.
Updating files: 100% (1998/1998), done.La struttura del catalogo risultante ./{bigtop} è all'incirca la seguente:
./bigtop-bigpetstore — applicazioni dimostrative, esempi sintetici
./bigtop-ci — strumenti CI, jenkins
./bigtop-data-generators — generazione di dati, sintesi, per smoke test etc.
./bigtop-deploy — strumenti per il deployment
./bigtop-packages — configurazioni, script, patch per la compilazione, parte principale dello strumento
./bigtop-test-framework — framework di testing
./bigtop-tests — i test stessi, di carico e smoke
./bigtop_toolchain — ambiente di compilazione, preparazione dell'ambiente per il funzionamento dello strumento
./build — cartella di lavoro per la compilazione
./dl — cartella per i sorgenti scaricati
./docker — compilazione in immagini docker, testing
./gradle — configurazione gradle
./output – cartella in cui vengono archiviati gli artefatti di compilazione
./provisioner — provisioning
Il punto più interessante a questo stadio per noi è la configurazione principale ./bigtop/bigtop.bom, in cui vediamo tutti i componenti supportati con le versioni. Qui possiamo specificare una versione diversa del prodotto (se vogliamo provare a compilarla) o una versione di build (se, ad esempio, abbiamo aggiunto una patch significativa).
Inoltre, suscita molto interesse la sottocartella .\/bigtop\/bigtop-packages, che ha un diretto legame con il processo di compilazione dei componenti e dei pacchetti con essi.
Quindi, abbiamo scaricato l'archivio, lo abbiamo estratto o abbiamo fatto un clone da github, possiamo iniziare la compilazione?
No, prima prepariamo l'ambiente.
Preparazione dell'ambiente
E qui è necessario fare una piccola digressione. Per la compilazione di praticamente qualsiasi prodotto, anche solo minimamente complesso, è necessario un determinato ambiente: nel nostro caso, si tratta di JDK, le stesse librerie condivise, file di intestazione, ecc., strumenti come ant, ivy2 e molto altro ancora. Una delle opzioni per ottenere l'ambiente necessario per Bigtop è l'installazione dei componenti richiesti sull'host di compilazione. Potrei sbagliarmi con la cronologia, ma mi sembra che dalla versione 1.0 sia stata introdotta anche l'opzione di compilazione in immagini docker preconfigurate e disponibili, che possono essere consultate qui.
Per quanto riguarda la preparazione dell'ambiente, c'è un assistente: Puppet.
Possiamo utilizzare i seguenti comandi, l'esecuzione avviene dalla directory principale
dello strumento, .\/bigtop:
.\/gradlew toolchain\n.\/gradlew toolchain-devtools\n.\/gradlew toolchain-puppetmodules
Oppure direttamente tramite puppet:
puppet apply --modulepath= -e "include bigtop_toolchain::installer"\npuppet apply --modulepath= -e "include bigtop_toolchain::deployment-tools"\npuppet apply --modulepath= -e "include bigtop_toolchain::development-tools"Sfortunatamente, già a questo punto possono sorgere difficoltà. Un consiglio generale qui è di utilizzare una distribuzione supportata, aggiornata sull'host di compilazione oppure provare la strada con docker.
Compilazione
Cosa possiamo provare a compilare? La risposta a questa domanda la darà l'output del comando
.\/gradlew tasks Nella sezione Package tasks ci sono una serie di prodotti che sono artefatti finali di Bigtop.
Possono essere identificati dal suffisso -rpm o -pkg-ind (nel caso di una compilazione
in docker). Nel nostro caso, l'elemento più interessante è Hadoop.
Proviamo a eseguire una compilazione nell'ambiente del nostro server di build:
.\/gradlew hadoop-rpmBigtop scaricherà automaticamente il codice sorgente necessario per il componente specifico e inizierà la compilazione. Pertanto, il lavoro dello strumento è legato ai repository Maven e ad altre fonti, il che significa che ha bisogno di accesso a Internet.
Durante il lavoro viene generato un output standard. A volte, da esso e dai messaggi di errore, si può capire cosa sia andato storto. Altre volte è necessario ottenere informazioni aggiuntive. In questo caso, è utile aggiungere argomenti --info o --debug, e può essere utile anche –stacktrace. Esiste un modo semplice per creare un insieme di dati da utilizzare successivamente per le liste di distribuzione, la chiave --scan.
Con essa, bigtop raccoglierà tutte le informazioni e le esporrà in gradle, dopodiché fornirà un link,
seguendo il quale una persona competente sarà in grado di capire perché la compilazione non è riuscita.
È importante tenere presente che questa opzione può rendere pubbliche informazioni che preferireste non divulgare, come nomi utente, nodi, variabili d'ambiente, ecc., quindi fate attenzione.
Spesso gli errori sono il risultato dell'impossibilità di ottenere componenti necessari per la compilazione. Di solito, il problema può essere risolto creando una patch per correggere qualcosa nel sorgente, ad esempio, gli indirizzi in pom.xml nella cartella principale del sorgente. Questo viene fatto creando e posizionando la patch nella cartella appropriata .\/bigtop\/bigtop-packages\/src\/common\/oozie\/ patch, ad esempio, sotto forma di patch2-fix.diff.
--- a\/pom.xml
+++ b\/pom.xml
@@ -136,7 +136,7 @@
central
- http:\/\/repo1.maven.org\/maven2
+ https:\/\/repo1.maven.org\/maven2
false
Probabilmente, al momento della lettura di questo articolo, non sarà necessario fare voi stessi la correzione sopra indicata.
Quando si incorporano patch e modifiche nel meccanismo di compilazione, potrebbe essere necessario "resettare" la compilazione attraverso un comando di pulizia:
.\/gradlew hadoop-clean
> Task :hadoop_vardefines
> Task :hadoop-clean
BUILD SUCCESSFUL in 5s
2 actionable tasks: 2 executedQuesta operazione annullerà tutte le modifiche nella compilazione di questo componente e la compilazione verrà eseguita di nuovo. Questa volta cercheremo di compilare il progetto in un'immagine docker:
.\/gradlew -POS=centos-7 -Pprefix=1.2.1 hadoop-pkg-ind
> Task :hadoop-pkg-ind
Costruzione di hadoop-pkg 1.2.1 su centos-7 in Docker...
+++ dirname .\/bigtop-ci\/build.sh
++ cd .\/bigtop-ci\/..
++ pwd
+ BIGTOP_HOME=\/tmp\/bigtop
+ '[' 6 -eq 0 ']'
+ [[ 6 -gt 0 ]]
+ key=--prefix
+ case $key in
+ PREFIX=1.2.1
+ shift
+ shift
+ [[ 4 -gt 0 ]]
+ key=--os
+ case $key in
+ OS=centos-7
+ shift
+ shift
+ [[ 2 -gt 0 ]]
+ key=--target
+ case $key in
+ TARGET=hadoop-pkg
+ shift
+ shift
+ [[ 0 -gt 0 ]]
+ '[' -z x ']'
+ '[' -z x ']'
+ '[' '' == true ']'
+ IMAGE_NAME=bigtop\/slaves:1.2.1-centos-7
++ uname -m
+ ARCH=x86_64
+ '[' x86_64 '!=' x86_64 ']'
++ docker run -d bigtop\/slaves:1.2.1-centos-7 \/sbin\/init
+
CONTAINER_ID=0ce5ac5ca955b822a3e6c5eb3f477f0a152cd27d5487680f77e33fbe66b5bed8
+ trap 'docker rm -f
0ce5ac5ca955b822a3e6c5eb3f477f0a152cd27d5487680f77e33fbe66b5bed8' EXIT
....
molto output
....
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-yarn-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-mapreduce-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-namenode-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-secondarynamenode-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-zkfc-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-journalnode-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-datanode-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-httpfs-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-yarn-resourcemanager-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-yarn-nodemanager-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-yarn-proxyserver-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-yarn-timelineserver-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-mapreduce-historyserver-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-client-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-conf-pseudo-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-doc-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-libhdfs-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-libhdfs-devel-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-hdfs-fuse-2.8.5-1.el7.x86_64.rpm
Scritto: \/bigtop\/build\/hadoop\/rpm\/RPMS\/x86_64\/hadoop-debuginfo-2.8.5-1.el7.x86_64.rpm
+ umask 022
+ cd \/bigtop\/build\/hadoop\/rpm\/\/BUILD
+ cd hadoop-2.8.5-src
+ \/usr\/bin\/rm -rf \/bigtop\/build\/hadoop\/rpm\/BUILDROOT\/hadoop-2.8.5-1.el7.x86_64
Esecuzione(%clean): \/bin\/sh -e \/var\/tmp\/rpm-tmp.uQ2FCn
+ exit 0
+ umask 022
Esecuzione(--clean): \/bin\/sh -e \/var\/tmp\/rpm-tmp.CwDb22
+ cd \/bigtop\/build\/hadoop\/rpm\/\/BUILD
+ rm -rf hadoop-2.8.5-src
+ exit 0
[ant:touch] Creazione \/bigtop\/build\/hadoop\/.rpm
:hadoop-rpm (Thread[Task worker for ':',5,main]) completata. Tempo impiegato 38 min 1.151 sec.
:hadoop-pkg (Thread[Task worker for ':',5,main]) iniziato.
> Task :hadoop-pkg
Il compito ':hadoop-pkg' non è aggiornato perché:
Il compito non ha dichiarato output nonostante abbia eseguito azioni.
:hadoop-pkg (Thread[Task worker for ':',5,main]) completato. Tempo impiegato 0.0 sec.
BUILD RIUSCITO in 40m 37s
6 attività eseguibili: 6 eseguite
+ RESULT=0
+ mkdir -p output
+ docker cp
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb:\/bigtop\/build .
+ docker cp
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb:\/bigtop\/output .
+ docker rm -f ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
+ '[' 0 -ne 0 ']'
+ docker rm -f ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
Errore: Nessun container di questo tipo:
ac46014fd9501bdc86b6c67d08789fbdc6ee46a2645550ff6b6712f7d02ffebb
BUILD RIUSCITO in 41m 24s
1 attività eseguibile: 1 eseguitaLa compilazione è stata eseguita su CentOS, ma può essere eseguita anche su Ubuntu:
.\/gradlew -POS=ubuntu-16.04 -Pprefix=1.2.1 hadoop-pkg-indOltre alla compilazione dei pacchetti per diverse distribuzioni Linux, lo strumento è in grado di creare un repository con i pacchetti compilati, ad esempio:
.\/gradlew yumRicordiamo anche i test di smoke e il deployment in docker.
Creare un cluster di tre nodi:
.\/gradlew -Pnum_instances=3 docker-provisionerEseguire i test di smoke in un cluster di tre nodi:
.\/gradlew -Pnum_instances=3 -Prun_smoke_tests docker-provisionerEliminare il cluster:
.\/gradlew docker-provisioner-destroyOttenere comandi per connettersi all'interno dei contenitori docker:
.\/gradlew docker-provisioner-sshMostrare lo stato:
.\/gradlew docker-provisioner-statusPer maggiori dettagli sulle attività di deployment, è possibile consultare la documentazione.
Parlando di test, ce ne sono in numero piuttosto elevato, principalmente test di smoke e test di integrazione. La loro analisi esula dal contesto di questo articolo. Posso solo dire che la compilazione della distribuzione non è così complessa come potrebbe sembrare a prima vista. Tutti i componenti che utilizziamo nella nostra produzione sono stati compilati e i test relativi sono stati superati, inoltre non abbiamo riscontrato problemi nel loro deployment e nell'esecuzione di operazioni di base nell'ambiente di test.
Oltre ai componenti già presenti in Bigtop, è possibile aggiungere anche altre funzionalità, comprese le proprie sviluppate. Tutto questo si automatizza perfettamente ed è in linea con il concetto di CI/CD.
Conclusione
È evidente che la distribuzione creata in questo modo non dovrebbe essere immediatamente inviata in produzione. È necessario comprendere che se c'è una reale necessità di costruire e mantenere la propria distribuzione, è un investimento di tempo e denaro.
Tuttavia, con un approccio corretto e un team professionale, è possibile anche fare a meno di soluzioni commerciali.
È importante sottolineare che il progetto Bigtop ha bisogno di sviluppo e sembra che attualmente non ci sia uno sviluppo attivo in corso. Inoltre, non è chiara la prospettiva per l'introduzione di Hadoop 3. A proposito, se hai una reale necessità di costruire Hadoop 3, puoi dare un'occhiata a di Arenadata, che oltre ai componenti standard
ha anche una serie di componenti aggiuntivi (Ranger, Knox, NiFi).
Per quanto riguarda Rostelecom, per noi Bigtop è una delle opzioni considerate al giorno d'oggi. Se opteremo per essa o meno, lo dirà il tempo.
Appendice
Per includere un nuovo componente nella build, è necessario aggiungere la sua descrizione in bigtop.bom e ./bigtop-packages. Puoi provare a farlo per analogia con i componenti esistenti. Prova a capire. Non è così difficile come sembra a prima vista.
E voi cosa ne pensate? Saremo felici di vedere il vostro parere nei commenti e grazie per l'attenzione!
Articolo preparato dal team di gestione dei dati di «Rostelecom»
Fonte: habr.com
