Continuous integration & continuous delivery pipeline til udvikling af selvkørende biler

Jeg har i forbindelse med faget store systemet på pba i softwareudvikling udarbejdet en synopsis om en continuous integration & continuous delivery pipeline til udvikling af software i selvkørende biler.

Indholdsfortegnelse

  • Afgræsning og problemformulering
  • Indledning
  • Docker
  • Continuous Integration
  • Continuous Delivery
  • Scale Cube & Grid computing
  • Sammenfatning

Afgræsning og problemformulering

Jeg har i de seneste par år fulgt med i udviklingen af de store software systemer, som der er i selvkørende elektriske biler. Jeg fandt det derfor oplagt at udvikle på en continuous integration og continuous delivery pipeline til mit eget konsulentfirma TB Coding og Combotto, som jeg kan bruge i de kommende år til udvikling af software til selvkørende elektriske biler. Min problemformulering til den bundne opgave i faget store systemer er som følgende:

Hvordan udvikles software til selvkørende biler fra ide til drift i et mindre konsulentfirma.

Indledning

Der er i de seneste par år sket en stor udvikling i bilbranchen, hvor mange af de store bilproducenter er begyndt på at udfase deres produktioner af benzin og diesel biler til nye produktioner af elektriske biler drevet af batterier. Elektriske biler kan hjælpe med at skåne miljøet på sigt, da de kan køre på vedvandende energi kilder såsom sol og vindenergi. Elektriske biler består af færre bilkomponenter i forhold til diesel og benzen biler, hvilket gør at elektriske biler på sigt kan produceres billigt, når underleverandører får deres produktion af bilkomponenter op i volumen. Elektriske biler er som standard elektriske, og det gør at der nemt kan integreres computer systemer og sensorer, som kan give ny funktionalitet til elektriske biler ved hjælp af software. Det kan fx være at man udvikler software, som gør at bilen kan køre af sig selv. Softwaren i elektriske biler kan i princippet opdateres løbende på samme måde som apps og operativ systemerne på vores smartphones. Det vil i de kommende år åbne op for mange nye forretningsmuligheder, og jeg ser derfor et stort behov for udvikling af værktøjer, som gør det hurtigere og nemmere at få udviklet store software systemer sikkert til elektriske biler. Der er rigtig mange software og hardware systemer i elektriske biler som spiller sammen, og det giver hurtigt en høj grad af kompleksitet. Elektriske biler har fx hardware og software til kontrol af selve bilen og displayet inde i bilen. Der kan også være hardware og software til parallel bearbejdning af store mængder sensor i realtid til selvkørende funktionalitet. Elektriske biler kan også gå på internettet, og det er derfor mulighed for brug af cloud teknologi.

Jeg bruger i øjeblikket ROS1 (robot operating system) til udvikling af software, som kan og bliver brugt i selvkørende biler. Her udvikler jeg i Linux Ubuntu2, og ROS er kort sagt baseret på C++ kode til den høje performance robotteknologi kræver, og python kode til bla. machine learning software. Jeg har så arbejdet videre med et CI/CD workflow, og her vil jeg komme ind på opsætning af Docker3 og Jenkins4 i et Linux operativsystem.

Docker

I TB Coding arbejder jeg primært på min stationære computer på mit kontor. Jeg bruger også min bærbar, når jeg er på farten. Andre gange arbejder på kundens computer. For at kunne være produktivt alle steder jeg er, har jeg et eller andet sted brug for den samme opsætning på mine computere for at kunne løse de opgaver jeg arbejder på. Hvis jeg tænker lidt tilbage, har jeg med årene brugt en del tid på opsætning af Linux Ubuntu operativsystem og udviklingstøjer, da jeg arbejder på flere computere. Denne tid kunne have være brugt bedre på fx at løse kundens opgaver.

Jeg har så fundet ud af, at der en god løsning på dette problem, og det er værktøjet Docker, som gør det muligt at arbejde i mindre virtuelle operativsystemer inde i ens operativsystem. Jeg arbejder primært med Linux Ubuntu, og her bruger jeg så Docker til at lave Docker containers, som er små mindre virtuelle Linux Ubuntu operativsystemer der kører inde i mit Linux Ubuntu operativsystem. Jeg kan fx lave en Docker container med den gamle Linux Ubuntu version 16.04, hvor jeg installerer en ældre version af ROS middleware og ældre python packages dertil. Deruodver kan jeg lave en anden Docker container med en nyere Linux Ubuntu version 18.04. Med Docker kan jeg nemmere arbejde i flere virtuelle udviklingsmiljøer på en gang, som passer præcist til projekternes behov uden at jeg skal lave om på mit eget operativsystem.

I mit tilfælde har jeg arbejdet med udvikling af software i ROS middleware, hvor jeg arbejder på software til selvkørende biler. Her har jeg opsat en Docker container med Linux Ubuntu version 18.04 og ROS melodic, som er den version af ROS frameworket som passer til Linux Ubuntu version 18.04. Min Docker container bliver lavet med en Dockefile, hvor jeg har beskrevet hvad der skal opsættes inde i Docker containeren. Jeg henter først et Jenkins baseimage ned fra Docker hub, som indeholder opsætningen af Jenkins og Linux Ubuntu. Derefter installeres der ROS-melodic og der kører et par shells scripts, så ROS-melodic er sat op i det virtuelle operativ system, og jeg kan derefter gå i gang med at udvikle. Dockerfilen med alt denne opsætning har jeg liggende på github, som jeg så kan hente ned til de forskellige computere jeg bruger i min hverdag, og jeg kan så hurtigt lave en Docker container med præcist den samme opsætning. Det er super smart, når jeg arbejder på flere computere og tester gamle og nye versioner af software i ROS.

Jeg havde dog en del udfordringer i forbindelse med opsætningen af mine docker containers. Der er en høj læringskurve i starten, som jeg skulle igennem før jeg begyndte at få en god forståelse for hvordan docker virker. Der var en hel del arbejde i Linux terminalen , hvor jeg skulle finde ud af at bruge mange forskellige docker kommandoer til at arbejde med docker. Det tog også en del tid før jeg fik min Dockefile til at virke ordentligt. docker build -t jenkins-master . er terminal kommandoen som jeg bruger til at builde min docker image fil, som jeg så kan lave til en docker container ved at køre docker run -p 8080:8080 –name=jenkins-master -dit jenkins-master. Jeg kan så starte min docker container ved at køre docker start jenkins-master, og jeg kan bruge docker exec -it jenkins-master bash til at gå ind og arbejde i min docker container.

Continuous Integration

Inde i min jenkins-master docker container har jeg opsat jenkins, som kører på localhost port 8080. Jenkins er en open source automations server, som jeg bruger til at opsætte en continuous integration og continuous delivery pipeline. Grunden til jeg har valgt jenkins er at det er det foretrukne værktøj i industrien til opsætning af CI/CD i ROS middlewaren. Der er ofte mange forskellige hardware og software packages i et robotprojekt, som er bygget op omkring ROS. Jenkins kan opdeles i flere jenkins instancer, som så kan gå ind og builde og teste de enkelte ROS packages. Det er ret smart i store udviklingsprojekter, hvor et team fx arbejder på en python computer vision package i ROS, og et andet team arbejder på en C++ path finder package i ROS.

Jeg har i mit projekt lavet et jenkins freestyle projekt, hvor jeg så har bygget automation til CI/CD. Jeg starter først med at hente kode ned fra github, hvor jeg har et privat repository med alt kode til ROS projektet, som jeg har arbejdet på. Dette ROS projekt består af en package med en talker, som kan publish data til et topic i ROS netværket. Jeg har så også lavet en listener, som kan gå ind og subscribe på et topic i ROS netværket, som bliver brugt til at lave en simple udregning. Jeg har udviklet unit test til koden, så jeg kan arbejder med test først i den måde jeg udvikler på. Alt denne kode er samlet i en enkelt ROS package, så koden holdes adskilt fra start på projektet. Hver package holdes adskilt i ROS netværket, og denne at arbejde på minder meget om den her microservice arkitektur, hvor man får afkoblet systemet ud i små bidder, som forskellige team så kan arbejde på.

Jeg henter først koden ned fra github, og derefter får jeg jenkins til at source ROS-melodic middlewaren, så ROS kan tolkes i min docker container. Derefter kører jeg et build af ROS softwaren fra github. Hvis det går godt, går jenkins videre og kører alle mine unit test igennem. Alt dette sker på jenkins serveren som kører inde i min docker container. Jeg holder koden adskilt fra mit eget operativ system, når koden buildes og testes. Det gør at jeg potentielt nemmere ville kunne udvikle sammen med flere udviklere og på flere forskellige maskiner, da jeg builder og tester i et produktionslignende miljø.

Continuous Delivery

I mit continuous delivery workflow har jeg været ved arbejde med et test miljø, hvor jeg tester min ROS applikation i et produktionslignende miljø. Det første jeg har arbejdet på er en integrations test, hvor jeg tester alle komponenter samlet ved hjælp af ROS launch files. Her kører jeg først ROS core, som er selve masteren i ROS netværket. Derefter starter min talker og derefter min subscriber. Det er for at teste komponenter samlet i et rigtig ROS miljø inden det sendes i produktion. Der kan godt opstår fejl, hvis nogle nodes i ROS netværket fx publisher data til det samme topic.

Herefter kunne det have været spændende at kigge på performance testing, simuleringsværktøjer eller test af software på en rigtig selvkørende bil i et lukket miljø på en kørebane. Det er super vigtigt at få testes softwaren af i et produktions miljø inden det er klar til at gå i produktion. Da jeg har bygget min software op omkring ROS best practices, er der en stor sandsynlighed for at kunne få integreret softwaren i et lignende CI/CD miljø i en større virksomhed, som udvikler teknologi til selvkørende biler.

Scale Cube & Grid computing

Jeg har i forbindelse med opgaven, har jeg arbejdet på at få koblet min stationære computer og bærbar sammen ved hjælp af SSH. Det er en protokol, som jeg har brugt til krypteret fjernadgang til mine computere. Jeg har flere gange oplevet flaskehalse problemer i form af mangel på computer kraft, når jeg arbejder på min bærbar. Disse problemer opstår især når jeg arbejder på min bærbar med machine learning, da det kræver god computer kraft, når jeg træner et neuralt netværk med data. Jeg har brug for at skalere ud af på x aksen, hvis vi snakker AFK scale cube. Her har jeg så tænkt med frem til at bruge SSH til at give fjernadgang til min stationære computer, som har et godt grafikkort og en god cpu. Jeg kan så fra min bærbar sætte opgaver i gang til parallel udregning på min stationær computer.

I samme omgang har jeg været ved at teste min ROS software på mit lokale netværk, hvor jeg har kørt mit talker program på min bærbar, og så har jeg kørt mit listener program på min stationær computer for at skalere ud af på y aksen.

Sammenfatning

Jeg synes det har været meget lærerigt at opbygge min egen CI/CD pipeline i Docker og Jenkins, som er tilpasset ROS middlewaren. Docker gør det nemmere for mig at arbejde på tværs af computere, da jeg arbejder inde i virtuelle miljøer i form af docker containers. Docker hjælper mig hurtigere fra start, da alt opsætning er ens på tværs af enheder. Jenkins har jeg brugt som en automations server, hvor jeg har opsat continuous integration og continuous delivery til udvikling i ROS middlewaren. Her fik jeg bla. automatiseret git pull, build, unit testing og integration testing i et produktionslignende miljø. Nu har jeg et udviklingsmiljø, hvor jeg hurtigere kan gå fra ide til drift i mit konsulentfirma TB Coding.