Saya menyarankan agar Anda membiasakan diri dengan transkrip laporan oleh Alexander Sigachev dari Inventos "Proses pengembangan dan pengujian dengan Docker + Gitlab CI"
Mereka yang baru mulai mengimplementasikan proses pengembangan dan pengujian berdasarkan Docker + Gitlab CI sering mengajukan pertanyaan mendasar. Di mana untuk memulai? Bagaimana cara berorganisasi? Bagaimana cara menguji?
Laporan ini baik untuk memberi tahu Anda secara terstruktur tentang proses pengembangan dan pengujian menggunakan Docker dan Gitlab CI. Laporan 2017 sendiri. Saya pikir dari laporan ini Anda bisa menggambar dasar-dasar, metodologi, ide, pengalaman penggunaan.
Siapa yang peduli, tolong, di bawah kucing.
Nama saya Alexander Sigachev. Saya bekerja untuk Inventos. Saya akan bercerita tentang pengalaman saya menggunakan Docker dan bagaimana kami secara bertahap mengimplementasikannya pada proyek-proyek di perusahaan.
Topik: Proses pengembangan menggunakan Docker dan Gitlab CI.

Ini adalah pembicaraan saya yang kedua tentang Docker. Pada saat laporan pertama, kami menggunakan Docker hanya dalam Pengembangan pada mesin pengembangan. Jumlah karyawan yang menggunakan Docker adalah sekitar 2-3 orang. Lambat laun, pengalaman diperoleh dan kami bergerak sedikit lebih jauh. Tautan ke laporan pertama kami.
Apa yang akan ada dalam laporan ini? Kami akan membagikan pengalaman kami tentang rake mana yang kami kumpulkan, masalah apa yang kami pecahkan. Tidak di mana-mana itu indah, tetapi dibiarkan bergerak.
Moto kami adalah: meratakan segala yang dicapai oleh tangan kami.

Masalah apa yang kita pecahkan?
Ketika sebuah perusahaan memiliki beberapa tim, programmer adalah sumber daya bersama. Ada beberapa tahapan ketika seorang programmer ditarik keluar dari satu proyek dan diberikan untuk beberapa waktu ke proyek lain.
Agar programmer dapat dengan cepat menyelidiki hal itu, ia perlu mengunduh kode sumber proyek dan meluncurkan lingkungan sesegera mungkin, yang akan memungkinkannya untuk lebih lanjut menyelesaikan tugas-tugas proyek ini.
Biasanya, jika Anda memulai dari awal, maka dokumentasi dalam proyek tidak cukup. Hanya orang-orang tua yang memiliki informasi tentang cara mengatur. Karyawan secara mandiri mengatur tempat kerja mereka dalam satu hingga dua hari. Untuk mempercepat ini, kami menggunakan Docker.
Alasan berikutnya adalah standarisasi pengaturan dalam Pembangunan. Dalam pengalaman saya, pengembang selalu mengambil inisiatif. Dalam setiap kasus kelima, domain khusus dimasukkan, misalnya, vasya.dev. Terdekat adalah tetangga Petya, yang domainnya adalah petya.dev. Mereka sedang mengembangkan situs web atau komponen sistem menggunakan nama domain ini.
Ketika sistem tumbuh dan nama-nama domain ini mulai jatuh ke dalam konfigurasi, maka ada konflik lingkungan pengembangan dan jalur situs ditulis ulang.
Hal yang sama terjadi dengan pengaturan basis data. Seseorang tidak peduli dengan keamanan dan bekerja dengan kata sandi root yang kosong. Seseorang pada tahap instalasi MySQL meminta kata sandi dan kata sandinya ternyata adalah 123. Sering terjadi bahwa konfigurasi basis data terus berubah tergantung pada komit pengembang. Seseorang dikoreksi, seseorang tidak memperbaiki konfigurasi. Ada trik ketika kami mengeluarkan semacam test config di .gitignore
dan setiap pengembang harus menginstal database. Ini mempersulit proses awal. Antara lain, Anda perlu mengingat tentang database. Basis data harus diinisialisasi, kata sandi harus terdaftar, pengguna harus terdaftar, piring harus dibuat, dan sebagainya.
Masalah lain adalah berbagai versi perpustakaan. Sering terjadi bahwa pengembang bekerja dengan berbagai proyek. Ada proyek Legacy yang dimulai lima tahun lalu (dari 2017 - note. Ed.). Pada awalnya, kami mulai dengan MySQL 5.5. Ada juga proyek modern di mana kami mencoba untuk memperkenalkan versi MySQL yang lebih modern, misalnya 5.7 atau lebih lama (pada 2017 - note. Ed.)
Siapa pun yang bekerja dengan MySQL tahu bahwa pustaka ini menarik dependensi. Cukup bermasalah untuk menjalankan 2 pangkalan bersama. Paling tidak, bermasalah bagi pelanggan lama untuk terhubung ke database baru. Ini pada gilirannya menyebabkan beberapa masalah.
Masalah berikutnya adalah ketika pengembang bekerja pada mesin lokal, ia menggunakan sumber daya lokal, file lokal, RAM lokal. Semua interaksi pada saat mengembangkan solusi untuk masalah dilakukan dalam kerangka fakta bahwa ia bekerja pada satu mesin. Contohnya adalah ketika kita memiliki server backend di Production 3, dan pengembang menyimpan file ke direktori root dan dari sana nginx mengambil file untuk menanggapi permintaan. Ketika kode tersebut jatuh ke dalam Produksi, ternyata file tersebut ada di salah satu dari 3 server.
Sekarang arah layanan mikro sedang berkembang. Ketika kita membagi aplikasi besar kita menjadi beberapa komponen kecil yang saling berinteraksi. Ini memungkinkan Anda memilih teknologi untuk tumpukan tugas tertentu. Ini juga memungkinkan Anda berbagi pekerjaan dan bidang tanggung jawab antara pengembang.
Pengembang Frondend, berkembang di JS, praktis tidak memengaruhi Backend. Pengembang backend, pada gilirannya, mengembangkan, dalam kasus kami, Ruby on Rails dan tidak mengganggu Frondend. Interaksi dilakukan menggunakan API.
Sebagai bonus, dengan Docker kami dapat memanfaatkan sumber daya di Pementasan. Setiap proyek, karena kekhususannya, memerlukan pengaturan tertentu. Secara fisik, perlu untuk memilih server virtual dan mengkonfigurasinya secara terpisah, atau untuk berbagi beberapa jenis variabel lingkungan dan proyek dapat saling mempengaruhi tergantung pada versi perpustakaan.

Alat Apa yang kita gunakan
- Langsung Docker itu sendiri. Dockerfile menjelaskan ketergantungan satu aplikasi.
- Docker-compose adalah bundel yang menyatukan beberapa aplikasi Docker kami.
- GitLab kami gunakan untuk menyimpan kode sumber.
- Kami menggunakan GitLab-CI untuk integrasi sistem.

Laporan ini terdiri dari dua bagian.
Bagian pertama akan berbicara tentang cara menjalankan Docker pada mesin pengembangan.
Bagian kedua akan berbicara tentang bagaimana berinteraksi dengan GitLab, bagaimana kita menjalankan tes dan bagaimana kita menjalankan Staging.

Docker adalah teknologi yang memungkinkan (menggunakan pendekatan deklaratif) untuk menggambarkan komponen yang diperlukan. Ini adalah contoh Dockerfile. Di sini kami mengumumkan bahwa kami mewarisi dari gambar Ruby Docker resmi: 2.3.0. Ini berisi Ruby versi 2.3 yang diinstal. Kami memasang pustaka build dan NodeJS yang diperlukan. Kami menjelaskan bahwa kami membuat direktori /app
. Tetapkan direktori aplikasi ke direktori kerja. Dalam direktori ini kami menempatkan Gemfile dan Gemfile.lock minimum yang diperlukan. Kemudian kami membangun proyek yang memasang gambar dependensi ini. Kami mengindikasikan bahwa kontainer akan siap untuk mendengarkan pada port eksternal 3000. Perintah terakhir adalah perintah yang secara langsung meluncurkan aplikasi kita. Jika kita menjalankan perintah mulai proyek, aplikasi akan mencoba untuk mengeksekusi dan meluncurkan perintah yang ditentukan.

Ini adalah contoh minimal dari file komposisi buruh pelabuhan. Dalam hal ini, kami menunjukkan bahwa ada hubungan antara kedua wadah. Ini langsung ke layanan basis data dan layanan web. Aplikasi web kami dalam banyak kasus memerlukan beberapa jenis database sebagai backend untuk menyimpan data. Karena kita menggunakan MySQL, contohnya adalah dengan MySQL - tetapi tidak ada yang mencegah kita menggunakan beberapa jenis database teman (PostgreSQL, Redis).
Kami mengambil gambar 5.7.14 MySQL dari sumber resmi dengan hub Docker tidak berubah. Gambar yang bertanggung jawab atas aplikasi web kami, kami kumpulkan dari direktori saat ini. Dia, selama peluncuran pertama, mengumpulkan gambar untuk kami. Kemudian meluncurkan perintah yang kami jalankan di sini. Jika kita kembali, kita akan melihat bahwa perintah peluncuran melalui Puma telah ditentukan. Puma adalah layanan yang ditulis dalam Ruby. Dalam kasus kedua, kami mendefinisikan ulang. Perintah ini bisa sewenang-wenang tergantung pada kebutuhan atau tugas kita.
Kami juga menjelaskan apa yang Anda perlukan untuk meneruskan port pada mesin host kami dari 3.000 ke 3.000 kontainer port. Ini dilakukan secara otomatis menggunakan iptables dan mekanismenya sendiri, yang langsung disematkan di Docker.
Pengembang dapat, seperti sebelumnya, menerapkan ke alamat IP yang tersedia, misalnya, 127.0.0.1 alamat IP lokal atau eksternal mesin.
Baris terakhir mengatakan bahwa wadah web tergantung pada wadah db. Saat kami menyebut peluncuran wadah web, komposisi buruh pelabuhan akan memulai database untuk kami. Sudah di awal database (pada kenyataannya, setelah memulai wadah! Ini tidak menjamin kesiapan database), kami akan meluncurkan aplikasi, backend kami.
Ini memungkinkan Anda untuk menghindari kesalahan ketika database tidak dinaikkan dan memungkinkan Anda untuk menghemat sumber daya ketika kami menghentikan wadah basis data, membebaskan sumber daya untuk proyek-proyek lain.

Apa yang memberi kami penggunaan database buruh pelabuhan pada proyek. Kita semua pengembang memperbaiki versi MySQL. Ini memungkinkan Anda untuk menghindari beberapa kesalahan yang mungkin terjadi ketika ada perbedaan versi, ketika sintaks, konfigurasi, dan pengaturan default berubah. Ini memungkinkan Anda menentukan nama host umum untuk basis data, login, kata sandi. Kami menjauh dari nama kebun binatang dan konflik dalam file konfigurasi yang sebelumnya.
Kami dapat menggunakan konfigurasi yang lebih optimal untuk lingkungan Pengembangan, yang akan berbeda dari standarnya. MySQL dikonfigurasi secara default pada mesin yang lemah dan kinerjanya di luar kotak sangat rendah.

Docker memungkinkan Anda untuk menggunakan juru bahasa Python, Ruby, NodeJS, PHP dari versi yang diinginkan. Kami menyingkirkan kebutuhan untuk menggunakan semacam pengelola versi. Sebelumnya, Ruby menggunakan paket rpm, yang memungkinkan pengubahan versi tergantung pada proyeknya. Ini juga memungkinkan wadah Docker untuk memigrasi kode dengan lancar dan menggantinya bersama dengan dependensi. Kami tidak memiliki masalah memahami versi penerjemah dan kode. Untuk memutakhirkan versi, turunkan wadah lama dan angkat wadah baru. Jika terjadi kesalahan, kami dapat menurunkan wadah baru, menaikkan wadah lama.
Setelah merakit gambar, wadah dalam Pengembangan dan Produksi akan sama. Ini terutama berlaku untuk instalasi besar.
Di Frontend, kami menggunakan JavaScipt dan NodeJS.
Sekarang kami memiliki proyek terbaru di ReacJS. Pengembang menjalankan seluruh wadah dan dikembangkan menggunakan hot-reload.
Selanjutnya, tugas merakit JavaScipt diluncurkan dan kode yang dikumpulkan dalam statika diberikan melalui sumber daya nginx hemat.

Di sini saya memberikan diagram proyek terakhir kami.
Tugas apa yang Anda selesaikan? Kami memiliki kebutuhan untuk membangun sistem yang berinteraksi dengan perangkat seluler. Mereka mendapatkan data. Salah satu opsi adalah mengirim pemberitahuan push ke perangkat ini.
Apa yang telah kami lakukan untuk ini?
Kami dibagi menjadi beberapa komponen aplikasi seperti: bagian admin di JS, backend, yang berfungsi melalui antarmuka REST di bawah Ruby on Rails. Backend berinteraksi dengan database. Hasil yang dihasilkan diberikan kepada klien. Admin dengan backend dan basis data berinteraksi melalui antarmuka REST.
Kami juga perlu mengirim pemberitahuan push. Sebelum itu, kami memiliki proyek di mana mekanisme dilaksanakan yang bertanggung jawab untuk mengirimkan pemberitahuan ke platform seluler.
Kami mengembangkan skema seperti itu: operator dari browser berinteraksi dengan panel admin, panel admin berinteraksi dengan backend, tugasnya adalah mengirim pemberitahuan Push.
Pemberitahuan push berinteraksi dengan komponen lain yang diterapkan pada NodeJS.
Antrian sedang dibangun, dan kemudian mengirimkan pemberitahuan mengikuti mekanismenya sendiri.
Dua database diambil di sini. Saat ini, dengan bantuan Docker, kami menggunakan 2 database independen, yang sama sekali tidak terhubung satu sama lain. Selain itu, mereka memiliki jaringan virtual umum, dan data fisik disimpan di direktori yang berbeda di mesin pengembang.

Hal yang sama, tetapi dalam jumlah. Penggunaan kembali kode penting di sini.
Jika sebelumnya kita berbicara tentang menggunakan kembali kode dalam bentuk perpustakaan, dalam contoh ini layanan kami, yang menanggapi pemberitahuan push, digunakan kembali sebagai server sepenuhnya. Ini menyediakan API. Dan sudah dengan perkembangan baru kami berinteraksi dengannya.
Pada saat itu, kami menggunakan NodeJS versi 4. Sekarang (tahun 2017 - note. Ed.) Dalam perkembangan terakhir kami menggunakan versi 7 dari NodeJS. Tidak ada masalah dalam komponen baru untuk menarik versi perpustakaan baru.
Jika perlu, Anda dapat melakukan refactor dan meningkatkan versi NodeJS dari layanan push notification.
Dan jika kita dapat mempertahankan kompatibilitas API, maka kita dapat menggantinya dengan proyek lain yang digunakan sebelumnya.

Apa yang Anda perlu tambahkan Docker? Tambahkan Dockerfile ke repositori kami yang menjelaskan dependensi yang diperlukan. Dalam contoh ini, komponen dipecah oleh logika. Ini adalah satu set minimal pengembang backend.
Saat membuat proyek baru, buat Dockerfile, jelaskan ekosistem yang diinginkan (Python, Ruby, NodeJS). Susunan buruh pelabuhan menjelaskan ketergantungan yang diperlukan - database. Kami menjelaskan bahwa kami membutuhkan database versi ini dan itu, untuk menyimpan data di suatu tempat.
Kami menggunakan wadah ketiga yang terpisah dengan nginx untuk membuat statis. Anda dapat mengunggah gambar. Backend menempatkan mereka dalam volume yang disiapkan sebelumnya, yang juga dipasang dalam wadah dengan nginx, yang memberikan statis.
Untuk menyimpan konfigurasi nginx, mysql, kami menambahkan folder Docker, di mana kami menyimpan konfigurasi yang diperlukan. Ketika seorang pengembang membuat repositori git clone di mesinnya, ia sudah mendapatkan proyek yang siap untuk pengembangan lokal. Pertanyaannya tidak muncul port mana atau pengaturan mana yang diterapkan.

Selanjutnya, kami memiliki beberapa komponen: admin, inform-API, notifikasi push.
Untuk menjalankan semuanya, kami membuat repositori lain yang disebut aplikasi dockerized. Saat ini, kami menggunakan beberapa repositori hingga setiap komponen. Mereka hanya berbeda secara logis - di GitLab kelihatannya seperti folder, dan pada mesin pengembang, folder untuk proyek tertentu. Satu tingkat di bawah ini adalah komponen yang akan digabungkan.

Ini adalah contoh dari hanya isi dari aplikasi dockerized. Kami juga membawa katalog Docker di sini, di mana kami mengisi konfigurasi yang diperlukan untuk interaksi semua komponen. Ada README.md, yang secara singkat menjelaskan cara memulai proyek.
Di sini kami menggunakan dua file docker-compose. Ini dilakukan agar dapat berjalan dalam langkah-langkah. Ketika seorang pengembang bekerja dengan kernel, ia tidak perlu pemberitahuan Push, maka ia hanya meluncurkan file menulis buruh pelabuhan dan karenanya sumber daya disimpan.
Jika ada kebutuhan untuk integrasi dengan pemberitahuan push, maka docker-compose.yaml dan docker-compose-push.yaml diluncurkan.
Karena docker-compose.yaml dan docker-compose-push.yaml ada di folder, sebuah jaringan virtual tunggal secara otomatis dibuat.

Deskripsi komponen. Ini adalah file yang lebih maju yang bertanggung jawab untuk mengumpulkan komponen. Apa yang luar biasa di sini? Di sini kami memperkenalkan komponen penyeimbang.
Ini adalah gambar Docker yang sudah jadi di mana nginx diluncurkan dan aplikasi yang mendengarkan soket Docker. Dinamis, ketika wadah hidup dan mati, konfigurasi nginx akan menghasilkan ulang. Kami mendistribusikan penanganan komponen dengan nama domain tingkat ketiga.
Untuk lingkungan Pengembangan, kami menggunakan domain .dev - api.informer.dev. Aplikasi dengan domain .dev tersedia di mesin pengembang lokal.
Kemudian konfigurasi ditransfer ke setiap proyek dan semua proyek diluncurkan bersamaan pada saat yang sama.

Jika digambarkan secara grafis, ternyata klien adalah browser kami atau beberapa alat yang dengannya kami melakukan permintaan untuk penyeimbang.
Penyeimbang nama domain menentukan wadah mana yang akan diakses.
Ini bisa berupa nginx, yang memberikan area admin JS. Ini bisa berupa nginx, yang memberikan API atau file statis yang diberikan kepada nginx dalam bentuk memuat gambar.
Diagram menunjukkan bahwa kontainer terhubung oleh jaringan virtual dan disembunyikan di belakang proxy.
Di mesin pengembang, Anda dapat beralih ke wadah dengan mengetahui IP, tetapi kami pada dasarnya tidak menggunakan ini. Kebutuhan untuk perawatan langsung secara praktis tidak muncul.

Contoh apa yang harus dilihat untuk membuat aplikasi galangan? Menurut pendapat saya contoh yang baik adalah gambar buruh pelabuhan resmi untuk MySQL.
Cukup rumit. Ada banyak versi. Tetapi fungsinya memungkinkan Anda untuk memenuhi banyak kebutuhan yang mungkin timbul dalam proses pengembangan lebih lanjut. Jika Anda menghabiskan waktu dan mencari tahu bagaimana semua ini berinteraksi, maka saya pikir Anda tidak akan memiliki masalah dalam implementasi diri.
Di hub.docker.com, biasanya ada tautan ke github.com, yang menyediakan data mentah langsung dari mana Anda dapat mengumpulkan gambar sendiri.
Lebih lanjut dalam repositori ini adalah skrip docker-endpoint.sh, yang bertanggung jawab untuk inisialisasi awal dan untuk pemrosesan lebih lanjut dari peluncuran aplikasi.
Juga dalam contoh ini ada kemungkinan konfigurasi menggunakan variabel lingkungan. Dengan mendefinisikan variabel lingkungan ketika memulai wadah tunggal atau melalui docker-compose, kita dapat mengatakan bahwa kita perlu mengatur kata sandi kosong untuk buruh pelabuhan pada root di MySQL atau apa pun yang kita inginkan.
Ada opsi untuk membuat kata sandi acak. Kami mengatakan bahwa kami membutuhkan pengguna, kami perlu menetapkan kata sandi untuk pengguna, dan kami perlu membuat database.
Dalam proyek kami, kami sedikit menyatukan Dockerfile, yang bertanggung jawab untuk inisialisasi. Di sana, kami mengoreksi kebutuhan kami untuk membuat perpanjangan hak pengguna yang digunakan aplikasi. Ini memungkinkan di masa depan untuk hanya membuat database dari konsol aplikasi. Aplikasi Ruby memiliki perintah untuk membuat, memodifikasi, dan menghapus basis data.

Ini adalah contoh tampilan versi MySQL tertentu di github.com. Anda dapat membuka dockerfile dan melihat bagaimana instalasi terjadi di sana.
skrip docker-endpoint.sh bertanggung jawab atas titik masuk. Selama inisialisasi awal, beberapa langkah persiapan diperlukan dan semua tindakan ini diambil hanya untuk skrip inisialisasi.

Kami lolos ke bagian kedua.
Untuk menyimpan kode sumber, kami beralih ke gitlab. Ini adalah sistem yang cukup kuat yang memiliki antarmuka visual.
Salah satu komponen dari Gitlab adalah Gitlab CI. Ini memungkinkan Anda untuk menggambarkan perintah tindak lanjut yang selanjutnya akan digunakan untuk mengatur sistem pengiriman kode atau menjalankan pengujian otomatis.
Laporan Gitlab CI 2 https://goo.gl/uohKjI - laporan dari klub Ruby Russia - cukup rinci dan mungkin akan menarik bagi Anda.

Sekarang kita akan mempertimbangkan apa yang diperlukan untuk mengaktifkan Gitlab CI. Untuk memulai Gitlab CI, cukup bagi kami untuk meletakkan file .gitlab-ci.yml di root proyek.
Di sini kami menjelaskan bahwa kami ingin melakukan urutan kondisi seperti pengujian, penggunaan.
Kami menjalankan skrip yang secara langsung memanggil buruh pelabuhan-menyusun perakitan aplikasi kami. Ini adalah contoh backend.
Selanjutnya, kami mengatakan bahwa perlu untuk mendorong migrasi untuk mengubah database dan menjalankan tes.
Jika skrip dieksekusi dengan benar dan tidak mengembalikan kode kesalahan, maka, sesuai, sistem melanjutkan ke tahap kedua penyebaran.
Fase penyebaran saat ini diterapkan untuk pementasan. Kami tidak mengatur restart dengan lancar.
Kami secara paksa memadamkan semua kontainer, dan kemudian kami mengangkat semua kontainer lagi, dikumpulkan pada tahap pertama selama pengujian.
Kami menjalankannya untuk lingkungan variabel saat ini dari migrasi basis data, yang ditulis oleh pengembang.
Ada catatan yang berlaku ini hanya untuk cabang master.
Saat mengganti cabang lain tidak dijalankan.
Dimungkinkan untuk mengatur peluncuran di cabang-cabang.

Untuk mengatur ini lebih lanjut, kita perlu menginstal Gitlab Runner.
Utilitas ini ditulis dalam Golang. Ini adalah file tunggal seperti biasa di dunia Golang, yang tidak memerlukan dependensi.
Saat startup, kami mendaftarkan Gitlab Runner.
Kami mendapatkan kunci di antarmuka web Gitlab.
Kemudian kita memanggil perintah init pada baris perintah.
Konfigurasikan Gitlab Runner dalam mode dialog (Shell, Docker, VirtualBox, SSH)
Kode pada Gitlab Runner akan dijalankan di setiap commit, tergantung pada pengaturan .gitlab-ci.yml.

Tampilan visualnya di Gitlab dalam antarmuka web. Setelah menghubungkan GItlab CI, sebuah bendera muncul yang menunjukkan status build saat ini.
Kami melihat bahwa komit dibuat 4 menit yang lalu, yang lulus semua tes dan tidak menimbulkan masalah.

Kita bisa melihat bangunan lebih detail. Di sini kita melihat bahwa dua negara telah berlalu. Menguji status dan status penempatan pada pementasan.
Jika kita mengklik build tertentu, maka akan ada output konsol dari perintah yang diluncurkan dalam proses sesuai dengan .gitlab-ci.yml.

Ini adalah bagaimana sejarah produk kita terlihat. Kami melihat bahwa ada upaya yang berhasil. Ketika tes diserahkan, itu tidak melanjutkan ke langkah berikutnya dan kode untuk staging tidak diperbarui.

Tugas apa yang kita selesaikan tentang pementasan ketika kita memperkenalkan buruh pelabuhan? , , , .
.
Docker-compose .
, Docker . Docker-compose .
, .
— staging .
production 80 443 , WEB.

? Gitlab Runner .
Gitlab Gitlab Runner, - , .
Gitlab Runner, .
nginx-proxy .
, . .
80 , .

? root. root root .
, root , root.
- , , , , .
? , .
, ?
ID (UID) ID (GID).
ID 1000.
Ubuntu. Ubuntu ID 1000.

?
Docker. , . , - , .
, .
.
Docker Docker Swarm, . - Docker Swarm.
. . . web-.
