git-merge: the github conference

This is the list and summary of talks of the conference day, what last on me.

The future of free software.

In this talk Deb Nicholson talk about free software and the future.
First of all she describe future, first by its view as a young girl, then using words from William Gibson: “The future is now, it is just not evenly distributed”.
So the future should be better distribuited, and free software should play this role, to distribuite the power to users.

Tales in scalability … google …

In this talk Ivan Frade and Minh Thai explain the challenge to manage huge git repositories: Android and Chromium.
Ivan Frade explained the use of a bitmap for tree and references, such that every commit relation to others is coded into a map of bit: 1 means that it is related, 0 that is not.

The What, how and why of scaling repositories

In this talk Johan Abildskov expose some use case and how companies suppose to scale repository. There are 2 main strategies: a mono repository, and a many repositories policy.
He advocates “Accelerate, the Science of DevOps”, a book that analyses which are the reasons to choose one or the other option, in this and all that cases where DevOps choices are under consideration.

Transition Git to SHA256

Brian Carlson explain the phases setted to switch existing repositories from SHA1 to SHA2. Due to its distribuited nature, every git repository manage its state in all the place where a developer maintain its cloned repository, so everything is inside its .git folder, and arranged there.
The git CLI manage every commit by signing (by hash function) the current state and the dependency to its parent. The strategy to switch from SHA1 hash function to SHA256 is diveded into phases, starting from the first where only SHA1 is supported, then the middles ones where SHA1 and SHA256 are both supported, the ending with the very last where only SHA256 is supported, so all commits are identified by a 64 characters hashcode, and the 40-char length of SHA1 is no more understood

Git Protocols ….

Brandon Williams describe which are the new future that are introduced with git v2 protocol. Git natively support https, ssh and git protocols. For the first 2 protocols solving the versioning problem (to support both version) are solved by http-headers and by environment variable, respectively in https and ssh. But for git protocol, that is a native, binary protocol, the most optimized and quickier one, identifing old server from theirs reply was a challenging job. Brandon explained how all that was faced.

Git support for large object

Terry Parker expose the use of lfs, and cdn related problems, and partial clone option of git

Git for games: …

here John Austin dives into game development environment and how to manage repo in git, where there are large files that are not very well managed by a git due to distribuited nature and the needs for every developer to fetch all the repo.

He made a project, gitglobalgraph, that show something related to dependencies of tree in the git repos

The art of pacience

Belen Barros Pena is an interaction designer, and she does not know nothing about git.
She explain how she learnt to use git by example, by just using the command line.
What she underscores is that there is no simple way to explain git, because version control, distribuited, is a complex thing, so the only way to explain it is to work with the designer, and not for the designer, explains every time there is a problem how to use git command line to solve that problem.

Version control for law.

Ari Hershowitz compares congress and local parlaments lawyer work, with git diff, and try to make a translation between line changes (diff) and law-language, for mapping things into a repository, and back for the laweyer.

Git, the annotated notepad

Very accessible, but focused, talk that explain what is an atomic change and why it is important to commit every single logical change.
Aniket Subhash Kadam, independent developer

Version control for visual learner

Veronica Hanus explain his problem when she need associates a commit with a change visually, that is, changing a stylesheet is not visually evident from the commit message. She investigate on the use of puppeters/selenium driver and such, to automate such a task.

Panel conversation

—- not really a talk

Gitbase a sql interface to git

it could be interesting

Microsoft windows into git

there are at least some option to optimize the use of git, and those was presented by the microsoft worker (at Azure), John Briggs

Git based education ….

This talk explain how git promote the use of a … TDD development.

The workshop

For some reason I decided to book the workshop too, because I have to admit that I really have problem with git, I like it but sometime I fight with it.

git

The more interesting tool presented during the workshop day was the visualizing tool

https://git-school.github.io/visualizing-git/

In the visualizing tool there is a command ‘undo’, that has no counterpart in git, but that make the tool more usable and the learning more confortable.

The most important command I learned, and of which I was not aware, is

git reflog

That is very usefull to show the log of reference changes.

Also the presentation of 10 git problems and their solution, really focus on problem that I have all the day and I need to solve (but I am not good at it).

A full day of workshops focusing on git tool seems too much, but it is a tool that I use all the day for a long time now, but without really understand the concept behind it. As Belen Barros Peña said in her talk, the art of patience, the better way to explain git to a no developer is by example command, but that apply to developer too, because what I found when I tried to read the documentation was a pile of manpages that document every single command with all possible use and option, and some other document presenting the concept behind git. I am sure I had buyed a book too, talking about git. But at the end there was little relation between concept exposed and real git command.

What I learned is that ‘git reflog’ is really valuable, but also that the only way to understand how to solve a problem is to face that problem, as said by Briana Swift, more and more, in order to interiorize the problem and the relative solution.

https://github.com/brianamarie/10-git-problems

DevOps

Other theme is about the patterns that could be implemented on using git. That means the policy to be followed, the opportunity to protect a branch, the definition of (how many) branches.

https://datasift.github.io/gitflow/IntroducingGitFlow.html

Also there exist different option for the repository: many repo, one repo. Me and the company I am working for, are using the many repo arrangement, and the idea to have a single repo is not really appealing to me, but I discovered it exists git submodule, I do not know if it is related.

Another interesting tool I discovered is Gerrit

https://www.gerritcodereview.com/

a collaboration tool that I probably want to introduce in the company

Also, during the conference there was a presentation of Jenkins X, but it was during lunch break. For what I could understand it is a command line tool (CLI) that setup pipelines on a Continuous Integration tool, and it permit to control the setted pipelines by the CLI. We are currently using JenkinsCI and I am ok with the pipeline defined in a Jenkinsfile.

Other CI tool everybody is talking about is CircleCI, I do not know which advances it has over Jenkins, maybe a native/natural support for docker-compose?

php zmq in docker and checking whether the C compiler works… no

 I spent 2 hours of what it lasts of my life trying to understand what was the problem on installing php’s zmq extension in a docker running alpine as base image. I would like to share my experience here.

 During morning I would like to write supporting class for integrating zmq into our system and use it from inside containers where services are  supposed to run.

First I just added to Dockerfile the pecl install command, and expected it works:

 

FROM php:7-cli-alpine
RUN apk add zeromq libzmq
RUN pecl install zmq-beta \
   && docker-php-ext-enable zmq


 

hey, docker hub specification says there should be no problem (rif. https://hub.docker.com/_/php/  # PECL extensions )

 

The message was:

> docker build .
[blah blah check that worked]
checking whether the C compiler works... no
configure: error: in `/tmp/pear/temp/pear-build-defaultuserEhCEfp/zmq-1.1.3':
configure: error: C compiler cannot create executables
See `config.log' for more details

and no way to find this config.log :

> docker run –rm xxxx ls /tmp/pear/

no such file. In fact pecl cleanup its building folder everytime, even if it fails. (why?? or bigger: WHY??)

I started with a reduced image, just 

FROM php:7-cli-alpine
RUN apk add zeromq libzmq

I ran:

inside_docker> pecl install zmq-beta
you do not have autoconf!
inside_docker> apk add autoconf
...
inside_docker> pecl install zmq-beta 

no way, no config.log.

I am a bit nervouse, I asked my collegue, a PHP expert … “Sorry, I’m not aware of this completely”. More nervouse. Some food.

Tried in my machine, a debian, and pecl install worked.

I got source from git (now I follow http://zeromq.org/bindings:php )

inside_docker> git clone git://github.com/mkoppanen/php-zmq.git
...no git command
inside_docker> apk add git
..[repeat again]
inside_docker> cd php-zmq
inside_docker> phpize
... no phpize
inside_docker> apk add phpize
inside_docker> phpize
inside_docker> ./configure
....[blah ...]

check config.log

And now it exists! but, what?!?

configure:2697: cc -V >&5
cc: error: unrecognized command line option '-V'
cc: fatal error: no input files
compilation terminated.
configure:2708: $? = 1
configure:2697: cc -qversion >&5
cc: error: unrecognized command line option '-qversion'; did you mean '--version'?
cc: fatal error: no input files
compilation terminated.
configure:2708: $? = 1
configure:2728: checking whether the C compiler works
configure:2750: cc    conftest.c  >&5
/usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find Scrt1.o: No such file or directory
/usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find crti.o: No such file or directory
/usr/lib/gcc/x86_64-alpine-linux-musl/6.4.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lssp_nonshared
collect2: error: ld returned 1 exit status
configure:2754: $? = 1
configure:2792: result: no
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME ""
...

what is -qversion ? it looks wrong … (I wasted some more time checking that)

some line above this:

Target: x86_64-alpine-linux-musl

Configured with: /home/buildozer/aports/main/gcc/src/gcc-6.4.0/configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --build=x86_64-alpine-linux-musl --host=x86_64-alpine-linux-musl --target=x86_64-alpine-linux-musl --with-pkgversion='Alpine 6.4.0' --enable-checking=release --disable-fixed-point --disable-libstdcxx-pch --disable-multilib --disable-nls --disable-werror --disable-symvers --enable-__cxa_atexit --enable-default-pie --enable-cloog-backend --enable-languages=c,c++,objc,java,fortran,ada --disable-libssp --disable-libmpx --disable-libmudflap --disable-libsanitizer --enable-shared --enable-threads --enable-tls --with-system-zlib --with-linker-hash-style=gnu
Thread model: posix
gcc version 6.4.0 (Alpine 6.4.0)

I decided to compare with the config.log created in my debian machine. I splitted the lines:

../src/configure -v
--with-pkgversion='Ubuntu 7.3.0-27ubuntu1~18.04'
--with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs
--enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++
 --prefix=/usr
 --with-gcc-major-version-only
 --program-suffix=-7
 --program-prefix=x86_64-linux-gnu-
 --enable-shared
 --enable-linker-build-id
 --libexecdir=/usr/lib
 --without-included-gettext
 --enable-threads=posix
 --libdir=/usr/lib
 --enable-nls
 --with-sysroot=/
 --enable-clocale=gnu
 --enable-libstdcxx-debug
 --enable-libstdcxx-time=yes
 --with-default-libstdcxx-abi=new
 --enable-gnu-unique-object
 --disable-vtable-verify
 --enable-libmpx --enable-plugin
 --enable-default-pie
 --with-system-zlib
 --with-target-system-zlib
 --enable-objc-gc=auto
 --enable-multiarch
 --disable-werror
 --with-arch-32=i686
 --with-abi=m64
 --with-multilib-list=m32,m64,mx32
 --enable-multilib
 --with-tune=generic
 --enable-offload-targets=nvptx-none
 --without-cuda-driver
 --enable-checking=release
 --build=x86_64-linux-gnu
 --host=x86_64-linux-gnu
 --target=x86_64-linux-gnu


/home/buildozer/aports/main/gcc/src/gcc-6.4.0/configure --prefix=/usr
 --mandir=/usr/share/man
 --infodir=/usr/share/info
 --build=x86_64-alpine-linux-musl
 --host=x86_64-alpine-linux-musl
 --target=x86_64-alpine-linux-musl
 --with-pkgversion='Alpine 6.4.0'
 --enable-checking=release
 --disable-fixed-point
 --disable-libstdcxx-pch
 --disable-multilib
 --disable-nls
 --disable-werror
 --disable-symvers
 --enable-__cxa_atexit
 --enable-default-pie
 --enable-cloog-backend
 --enable-languages=c,c++,objc,java,fortran,ada
 --disable-libssp
 --disable-libmpx
 --disable-libmudflap
 --disable-libsanitizer
 --enable-shared
 --enable-threads
 --enable-tls
 --with-system-zlib
 --with-linker-hash-style=gnu

I asked the internet: what is multilib? is not possible to have m32 on alpine and blah … ( https://stackoverflow.com/questions/40539592/how-to-compile-a-32bit-hello-world-on-alpine ). Fuck. I just want something like:

inside_docker> apk add build-base

and then … pecl:

 

inside_docker> pecl install zmq-beta

 

It run! It works. So my Dockerfile:

FROM php:7-cli-alpine
RUN apk add autoconf gcc libzmq zeromq-dev zeromq coreutils build-base
RUN pecl install zmq-beta \
   && docker-php-ext-enable zmq

That’s all. Now I can start the real work.

News from Verona ( ReactJS Day – October, 5th, 2018)

I wrote some kind of report about ReacJS day – Verona, October, 5th. But my pc blocked (TODO: buy a new pc, once I understand which), I did not saved the document. I taked a screenshot.

My experiment on React.context will focus on edit state of a page. Currently the page is made of various components and some are switchable to edit-mode and view-mode. I want to add constraint that only one element in a page is on edit mode, and also to add the behavior of switch-to-view-mode-on-ESC-key.

I should provide a value via EditState.provider : elementid

For this I need that every editable element have a unique id in the page.

Some faced it in https://github.com/facebook/react/issues/1137, the most immediate and simple proposed solution is
https://github.com/facebook/react/issues/1137#issuecomment-95699269

But I will skip this problem passing a register function

const EditStateContext = React.createContext( {
   editElement: null,
   register: () => {}, // return an unique id
   editModeOn: (id) => {}, // toggle on
   editModeOff: (id) => {} // toggle off
})

as documented the value should be the state of a containing component

import { EditStateContext } from './EditStateContext';
class App extends React.Component {
  constructor(props) {
    super(props);
    this.editableComponents = [];
    this.register = () => {
	let newLength = this.editableComponents.push(this.editableComponents.length);
	return newLength - 1; // this is enough to stay safe on race condition
    }
    this.editModeOn = (id) => {this.setState({editElement:id})}
    this.editModeOff = (id) => {this.setState((oldState) => { if (oldState.editElement ===id) {return {editElement:id} }} )}
    this.state = {
	// about js lang I dislike the use of -1 for notFound of indexOf, but ...
	editElement: -1,
	register: this.register,
	editModeOn: this.editModeOn,
	editModeOff: this.editModeOff
    }
  }
  componentDidMount() {
	document.addEventListener('onkeyup',(e) => {
		if (e.code === 'ESC') { // Replace with something meaninful
			this.setState(state=>{ return {editElement: -1 }} ));
		}
	});
  }
  render() {
	return (
		<EditStateContext.Provider value={this.state}>
		  <Content />
		</EditStateContext.Provider>
	);
  }
}

The consumer will receive the value

import { EditStateContext } from './EditStateContext';

function withSkipEditableEl(Element) {
   return (
	<EditStateContext.Consumer>
		{ (props) => (<Element ...props />) }
	</EditStateContext.Consumer>
   )
}

Now I can use that HOC function passing the editable element.

It may works, I will test tomorrow.

I am still confused about contexxt and a number of pending tasks on the go.

Docker in a Docker

Running a docker container from inside a docker container, I mean.

Of course one can define an image that instanciate a container as its default command, and this would lead to an infinite loop of forks … let’s see

The infinite containment

docker run -v /var/run/docker.sock:/var/run/docker.sock -name whocare alwaysfork

Ok, that is bad and I will not describe.

Container near a container

Maybe it is a bad thing, but most of the time docker and container is used interchangely, so I would had better written docker near a docker, that is cool.

What is near and why not “in”? it is like the infinite containment example, it is near because every contained execution is managed by the main daemon (dockerd) running in the host machine.

In fact in a infiniete containement you are not forking endless, but you are asking the dockerd to instanciate endlessly a new container, there is nothing that make one of the container a manager of the other, or a more authoritative manager than the other: every container that can access the /var/run/docker.sock socket and has the right can stop/remove every container in the machine.

Security concerns

I am not expert of security concerns, but everytime you do something “strange” there are great chances that that “strangeness” could lead to a security hole. (not being an expert I think even “not-strange” done by me can imply bad things)

Here the problem is due to the way docker is managing user, and mostly by how it manage the uid=0, root. The command by itself run the image standard command, and it is expected that the Dockerfile specify USER that will run the default command (and that is something != root).

But the weird part here is that being actually a container-near-container situation, at every instanciate point it could be switched to root with a

docker exec -u root -it myfunnyimage ./abadcommandforyou

this could be run from any container, call it aquitecontainer, all that is needed is the docker command in the image of aquitecontainer and that the socket is mounted as -v /var/run/docker.sock:/var/run/docker.sock and … so?

So you can switch to root from a container not running as root, because you can see the socket, and this is enough.

Two case are given:

  1. the containing container is running as root, so no particular needs to access the socket
  2. the containing container is running as a unprivileged user, but it has access to socket, so no particular needs to access the socket from the anyuserisused inside
  3. the containing container is instanciated by root, but running as unprivileged user, that again map to the calling user, that is root

Yes, the problem here is that docker daemon always map the “no-root” user to the uid of the user that call its api.

But really it is not enough

In fact to access /var/run/docker.sock a user must be part of docker group, when a container is instanciated with its default user the groups are not migrated, so the image’s definition of user’s group membership is something to take into account: if internal user of the docker has no access to the docker.sock it can not communicate with the dockerd running, so no more docker in docker, no more root migration

A matter of elegance

I need some moment to fully understand this:

const compose = ( ...fns ) => fns.reduce( ( f, g ) => ( ...args ) => f( g( ...args ) ) );

reduce method is trickly: when initialValue is not given, the first element of the array is taken as first argument of reduce’s callback parameter, so f is the first argument, g is the second, (…args) is the formal parameters (passed to the resulting function), at the end of the reduction all …fns are applyied in reverse order (i.e. compose(f,g,h) g is applyed before f, and h is applyed before g, resulting in (…args) => f(g(h(…args)) ).

But once I got it it happen to be really an elegant way to write it:

const $d = $data.mergeMap( compose(Rx.Observable.from, r=>r.split('\n')) );

and not:

const $d = $data.mergeMap(r=>Rx.Observable.from(r.split('\n')));

that is less readable

Lo sporco lavoro del CI/CD e DevOps

Ora racconto una storia. Beh, la faccio breve, si è fatta una certa.

 

Da quando c’è bisogno di rilasciare il software in tempo reale sono stati scritti diversi software di supporto per fare lo sporco lavoro di: eseguire test, impacchettare, distribuire i pacchetti nei vari server di destinazioni.

Uno di questi è Jenkins, scritto in Groovy che è un linguaggio funzionale che compila per JVM.

A marzo dello scorso anno ho visto una presentazione di un tipo delle RedHat che usava appunto Jenkins e Gogs (repo a la github minimale). Ovviamente siccome dove lavoro siamo all’età della pietra per quanto riguarda il Continuous Integration e Delivery, ho deciso che dovevo implementare questo.

Così è da inizio gennaio che tra influenza e maldistomaco ho messo su Jenkins facendolo parlare con gogs (già in uso da quasi un mese) … cioè in realtà è gogs che manda un messaggio a Jenkins quando gli arriva un push.

Per rendere la cosa più stagna ho installato gogs e jenkins in propri dockers e lo ip è indicato staticamente e numericamente perché l’interfaccia bridge di default non prevede la risoluzione per nome (mentre definendo una rete specifica magicamente dovrebbero essere risolti gli indirizzi col nome o id dell’immagine, ma sono cose che correggerò in futuro, forse)

Bene o non bene, fino a quando lunedì decido che anche l’applicazione electron che sto scrivendo deve fare il build in automatico, e sta volta arrivano i guai.

1. Jenkins esegue il build in un docker che va a creare subito dopo aver scaricato il repo (e sì, basta passare /var/run/docker.sock come volume al docker dove gira Jenkins, e il client all’interno del docker Jenkins va a comunicare col demone docker dell’host: trovo che sia una figata).

2. Electron non gli sta mica bene che usi un docker minimale tipo alpine. Questo è semplice c’è da usare electronuserland/builder:wine

3. devo sbatterci un po’ perché in un primo momento provo ad usare babel 7.xx, che è in beta, e quindi modifico .babelrc, e poi altri file che fanno riferimento a babel, ma viene fuori che webpack di lavorare con babel 7 non ne vuole sapere quindi torno indietro a 6.23, che è comunque ok, ma come mi passa per la testa, eccetera. Poi npm install non funziona e lamenta qualcosa di incomprensibile (non trova il modulo file, flow-typed? ma che vai cercando??) e trovo https://github.com/react-boilerplate/react-boilerplate/issues/1278#issuecomment-281121561 “One of the things that can cause this bug is adding packages to the wrong dependency section. For instance yarn add gulp will add it to dependencies instead of devDependencies”
… e poi? poi c’è che vuole pubblicare chissadove il pacchetto debian, che non so neanche perché lo sto facendo. e devo aggiungere –publish never
E siamo a mercoledì. In realtà per via del fuso siamo a giovedì … fuso? sì.

E le Promise ritornano (risolvono in) function?

Stasera ero qui con un test (acceptance) cercando di accrocchiarlo alla meglio.
In sostanza usando jsdom e jest ho del codice legacy che utilizza jquery (versione vecchissima) e il js è nella pagina. Lo incollo in un file separato, prepare.js. E visto che devo caricarlo tramite node lo metto dentro una funzione che chiamo con parametro $ (che è la jQuery). Tipo:
 
 
let start = ($) => {
   $(function() {
       var actions = ActionGroup($("#actions"));
      .... // e blablabla
      function loadExample() {
        const fs = require('fs');
        var exJson = fs.readFileSync(.....)
        actions.loadObject(JSON.parse(exJson);
     }
    loadExample();
   })
}
module.exports = start

Quindi posso eseguire un solo caso, testare un solo json. (e devo usare anche un timeout a caso per prima di fare expect blabla)

 
Ora arriva un nuovo caso da controllare, un nuovo json. E qui ho un attimo di delirio, penso che forse dovrei trasformare il tutto in una funzione, da usare come class, cioè instanziarla tramite la new … Oppure uso una promise che risolve in una function. Cioè:
 
let start = ($) => {
    return new Promise((resolve, reject) => {
        $(function() {
            actions e blablabla ....
            . ...

             function loadExample(filename) { // parametro
            .....
            ..}
            resolve(loadExample);
         });
    }); // non chiamo mai reject()
};
module.exports = start
 
e così quando la vado a chiamare ho:
 
let prepare = require('./prepare');
prepare(window.$).then((loadAction) => {
   loadAction('./path/tothe1.json');
   expect(window.$('#selector').html()).equals(blabla1);
   loadAction('./path/tothe2.json');
   expect(window.$('#selector').html()).equals(blabla2);
})
.catch( (err) => expect(false).equals(true) )
 
Siccome sono poco funzionale il cambiare 2 righe per ottenere questo m’è sembrata una figata

Observable. Prendo nota

Probabilmente in ritardo col resto del mondo, h chiarito un punto importante riguardo gli observable, e l’ho capita usando observable-redux. Prendo nota.

Definendo un Epic, da uno stream di action$ si restituisce un’altro stream di action

La Epic è eseguita dopo che il relativo reducer ha fatto il suo lavoro.

È possibile, data una action, restituirne un’altra, tramite .map()
in tal caso l’oggetto da restituire è proprio una action

È possibile inoltre restituire uno stream (un observable) che restituisce una (o più) action, in questo caso
si deve usare il metodo mergeMap()

Es.:

const loadOrdersEpic = (action$, store) => {
  return action$
  .ofType('LOADORDERS')
  .flatMap( () => { Observable.from(ajax('req')) })
  .mergeMap((res) => {
    return Observable.merge(
      Observable.of({type:'SUCCESSFULL.NET'}),
      Observable.of({type:'DATAREADY', res})
      );
    });
}

a differenza di map posso comporre degli observable(s) quindi generare più action (ovvero uno stream che genera più action)

const loadOrdersEpic = (action$, store) => {
  return action$
  .ofType('LOADORDERS')
  .flatMap( () => { Observable.from(ajax('req')) })
  .map((res) => {
    return {type:'DATAREADY', res}
   });
}

 

 

Cosa ho imparato oggi

Coso ho imparato oggi

(professore FONTECEDRO https://www.youtube.com/watch?v=aqTmhBca7f8 )

Dopo aver insistito col farmi dare un server da poter usare per metterci redmine e gogs, mi sono ritrovato oggi a dover far girare i due docker insieme e farli interagire.

C’è da dire che di docker non ci capisco nulla, quindi oggi ho imparato ad usare quello che mi serve di docker.

Prima di tutto sono container, ovvero sono basati sull’esecuzione di un processo bindato (perché dire bendato non da abbastanza l’idea) rispetto al resto del sistema. In sostanza quasi una macchina virtuale, ma gira sullo stesso kernel dell’os nel quale lo si lancia, è basato su concetto di cgroups di linux, e siccome non lo so rimando a https://en.wikipedia.org/wiki/Cgroups

Quello che interessava a me era di tirar su una immagine docker di redmine e una di gogs e farle girare nel server, e in più collegare i due container integrare un sistema per il controllo del progetto che desse delle statistiche aggiornate della situazione.

Ecco, quest’ultima parte è particolarmente complicata se non sai niente di docker.

*Come si fa girare un docker.*

Sostastanzialmente ho capito che per far girare un docker devi prima prendere l’immagine e poi avviarlo. Inizialmente avevo inteso che bastasse riferirsi alla immagine e scrivere

docker run image/name [altrivari parametri]

e così esso faceva tutto. Ho poi scoperto che questa è una visione un po’ miope. In effetti mi sono trovato con immagini nelle quali era già definito lo script di start. In generale al comando “docker run” si specifica il nome dell’immagine (che docker scarica in una qualche maniera da un repository delle immagini) e il comando da eseguire all’interno del container contestualmente creato al momento in cui viene eseguito run. Frase contorta, disgustorama, come direbbe il professor Fontecedro. Ma in realtà il comando

$ docker run -d -p 80:80 my_image nginx -g ‘daemon off;’
60baacd90721 # valore restituito

carica l’immagine my_image, crea un container, e, all’interno di quello esegue il comando “nginx -g ‘daemon off;'”.
Ora, visto che si tratta di una immagine personale, evidentemente devi essere a conoscenza che contiene il programma nginx, e quindi lo puoi eseguire. In generale io ho immagini nelle quali è definito all’interno dello script start.sh l’avvio di un server.

Ecco esattamente quello è il concetto di immagine: cosa c’è dentro il microservice che viene eseguito tramite docker.

Importante è anche il concetto di container: l’esecuzione della immagine con i relativi parametri di esecuzione.

Così, mi pare di aver capito, che se eseguo “docker run” con tutti i parametri del caso, ottengo un container id, è una chiave unica, sembra sha256, che identifica il container. A quel punto posso fermarla o riavviarla alla bisogna. Così:

docker stop 60baacd90721
docker start 60baacd90721

e 60baacd90721 è l’id del container che viene restuito dal comando “docker run”

Ho poi capito che se ho bisogno di entrare nella “quasi-macchina-virtuale” posso eseguire un comando a piacere in un virtual terminal di quella macchina, così

docker exec -ti 60baacd90721 bash

e posso specificare l’utente col quale eseguirlo

docker exec -u redmine -ti 60baacd90721 bash

perché avevo il problema di dover controllare il risultato del comando “git ls-remote -h ssh://…” per controllare l’accessibilità all’altro container.

A proposito del far girare più container sulla stessa macchina, il problema è stato farli communicare tra loro (magari con una sola m). E per questo c’è

docker network

sembra che docker sia un’insieme di sotto programmi, un po’ come è git. Quindi

docker network ls

elenca le reti definite nel sistema.

docker network inspect [networkname]

mostra la definizione della rete

docker network connect [networkname] [containerid]

connette una rete al container. E questa cosa è magica. In pratica se 2 container non riescono a vedersi è perché, generalmente, sono stati definiti tramite il comando run o tramite docker-compose. Nel primo caso il container avrà associata la rete “bridge” di default, nel secondo caso viene creata una rete on-the-fly da docker (c’è da controllare cosa sia docker-compose, il comando, per capire perché), e il suo nome è dato dal nome della definizione col postfisso “_default” (cioè se docker-compose.yaml è nella cartella “sfortuna” al momento della esecuzione di docker-compose, la rete creata si chiamerà sfortuna_default), nel mio caso si chiamava bugs:

$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
e0af7dce8070 bridge bridge local
ac43047ffe4f bugs_default bridge local
e117f156b39d host host local
b2a366b4b71a none null local

host è un tipo particolare di network, consiste nel risiedere nella stessa interfaccia del server dove gira … posso solo immaginare i casini nella gestione, ma è più veloce, evidentemente, perché non è emulata.

Ora, quello che ho trovato veramente fantistico oggi (eh, ma ho sudato parecchio per arrivarci) è proprio

docker network connect [netname] [containerid]

e

docker network disconnect [netname] [containerid]

in pratica si opera su un container esistente, e in esecuzione, e gli si aggiunge una scheda di rete virtuale, e la si toglie.

Cosmico.

È così che il container di redmine può vedere la rete del container gogs, e può richiedere cose tipo

git ls-remote -h ssh://git@172.17.0.2:10022/danieldock/privatetest.git

Ovviamente il viaggio di oggi è stato infarcito di “boh … non funziona, lascio stare .. ma…” e dal leggere cose tipo “I’ll merge if it is the case” https://github.com/dergachev/redmine_git_remote/issues/34 (no, che dici, quanti devono ancora scoronare?)

 

Ok. Tutto funziona e abbiamo un sistema per monitorare l’andamento dello sviluppo delle features, la gestione delle anomalie, vediamo chi sta lavorando a cosa e come, eccetera.

Era ora.

 

App cross platform basate su webengines.

====================================
Cross platform basati su webengines.
====================================

(o motori di rendering)

– inglobare una pagina web in una finestra del browser senza le limitazioni tipiche imposte dal browser (accesso al filesystem e ai vari dispositivi), per creare una applicazione nativa (più o meno)

– **Meteor**: applicazione js+html che non ha limitazioni di accesso al filesystem. Richiede l’installazione di node e di altri pacchetti nella macchina target, non crea un vero e proprio eseguibile, ovvero non compila il codice. Ha il vantaggio di avere come target anche

– **Electron**: permette di creare applicazione js+html senza limitazioni. In più compila nativamente il codice per la macchina target. Ha un rendiring engine basato su webkit (chromium) e non supporta target come iOS e Android per la compilazione.

– **Cordova**: framework pensato specificamente per dispositivi mobile. Cordova definisce una serie di plugin per accedere alle risorse del dispositivo, l’applicazione dichiara a quali risorse vuole poter accedere, quindi da Javascript sarà possibile richiamare i metodi ad esse associate, ovvero associati ai plugin caricati. Tutto questo è pensato per i dispositivi mobile dove la lista di permessi deve essere dichiarata al momento della installazione di una applicazione. Es.:

Dal punto di vista della applicazione js+html si può usare quello che si preferisce, ad esempio qui

si usa react + webpack

– **ionic** è semplicemente un framework basato su Cordova, con dei componenti standard che cerca di unificare e velocizzare la creazione di applicazioni per più target di Cordova, mantenendo la coerenza tra esse.

– **Positron** è stato un tentativo di usare il rendering engine di firefox per fare la stessa cosa che fa Electron. Poi *chiuso*.

– Servo based runtime (idea)

un backend in python e webkit per html+js. Da l’opportunità di usare moduli python per controllare la webview, ma ovviamente richiede l’installazione di python (analogamente a come Meteor richiede l’installazione di Node.js).

qualcosa di molto simile a Electron (firefox engine)

– Edge che vantaggi si hanno con Edge? si possono esportare moduli scritti in C# verso node.js, quindi usarli all’interno della webview.

un fork

– **ReactNative** non è un vero e proprio html+js, permette infatti di usare i componenti disponibili, e comporli per creare una applicazione, ma non l’html vero e proprio. Compila nativamente per iOS e Android, vere e proprie applicazioni native.

Questo articolo è una bozza, evidentemente.