Cara Membangun Pipeline Penerapan Awal yang Efektif
Diterbitkan: 2022-03-11Saya suka membangun sesuatu—pengembang apa yang tidak? Saya suka memikirkan solusi untuk masalah yang menarik, menulis implementasi, dan membuat kode yang indah. Namun, yang saya tidak suka adalah operasi . Operasi adalah segalanya yang tidak terlibat dalam membangun perangkat lunak yang hebat—mulai dari menyiapkan server hingga mengirimkan kode Anda ke produksi.
Ini menarik, karena sebagai pengembang Ruby on Rails freelance, saya sering harus membuat aplikasi web baru dan mengulangi proses mencari tahu sisi DevOps. Untungnya, setelah membuat lusinan aplikasi, saya akhirnya menetapkan jalur penyebaran awal yang sempurna. Sayangnya, tidak semua orang memahaminya seperti saya—akhirnya, pengetahuan ini menuntun saya untuk mengambil risiko dan mendokumentasikan proses saya.
Dalam artikel ini, saya akan memandu Anda melalui saluran sempurna saya untuk digunakan di awal proyek Anda. Dengan pipeline saya, setiap push diuji, cabang master di-deploy ke staging dengan dump database baru dari produksi, dan tag berversi di-deploy ke produksi dengan pencadangan dan migrasi yang terjadi secara otomatis.
Catatan, karena ini saluran saya , itu juga berpendirian dan sesuai dengan kebutuhan saya; namun, Anda dapat merasa bebas untuk menukar apa pun yang tidak Anda sukai dan menggantinya dengan apa pun yang Anda sukai. Untuk saluran saya, kami akan menggunakan:
- GitLab untuk meng-host kode.
- Mengapa: Klien saya lebih suka kode mereka tetap dirahasiakan, dan tingkat gratis GitLab luar biasa. Juga, CI gratis terintegrasi luar biasa. Terima kasih GitLab!
- Alternatif: GitHub, BitBucket, AWS CodeCommit, dan banyak lagi.
- GitLab CI untuk membangun, menguji, dan menerapkan kode kita.
- Mengapa: Ini terintegrasi dengan GitLab dan gratis!
- Alternatif: TravisCI, Codeship, CircleCI, DIY dengan Fabric8, dan banyak lagi.
- Heroku untuk meng-host aplikasi kami.
- Mengapa: Ini bekerja di luar kotak dan merupakan platform yang sempurna untuk memulai. Anda dapat mengubahnya di masa mendatang, tetapi tidak semua aplikasi baru perlu dijalankan pada kluster Kubernetes yang dibuat khusus. Bahkan Coinbase dimulai di Heroku.
- Alternatif: AWS, DigitalOcean, Vultr, DIY dengan Kubernetes, dan banyak lagi.
Sekolah Lama: Buat Aplikasi Dasar dan Terapkan ke Heroku
Pertama, mari kita buat ulang aplikasi khas untuk seseorang yang tidak menggunakan pipeline CI/CD mewah dan hanya ingin men-deploy aplikasi mereka.
Tidak masalah jenis aplikasi apa yang Anda buat, tetapi Anda akan memerlukan Yarn atau npm. Sebagai contoh saya, saya membuat aplikasi Ruby on Rails karena dilengkapi dengan migrasi dan CLI, dan saya sudah memiliki konfigurasi yang ditulis untuk itu. Anda dipersilakan untuk menggunakan kerangka kerja atau bahasa apa pun yang Anda inginkan, tetapi Anda memerlukan Yarn untuk melakukan pembuatan versi yang akan saya lakukan nanti. Saya membuat aplikasi CRUD sederhana hanya menggunakan beberapa perintah dan tanpa otentikasi.
Dan mari kita uji apakah aplikasi kita berjalan seperti yang diharapkan. Saya melanjutkan dan membuat beberapa posting, hanya untuk memastikan.
Dan mari kita terapkan ke Heroku dengan mendorong kode kita dan menjalankan migrasi
$ heroku create toptal-pipeline Creating ⬢ toptal-pipeline... done https://toptal-pipeline.herokuapp.com/ | https://git.heroku.com/toptal-pipeline.git $ git push heroku master Counting objects: 132, done. ... To https://git.heroku.com/toptal-pipeline.git * [new branch] master -> master $ heroku run rails db:migrate Running rails db:migrate on ⬢ toptal-pipeline... up, run.9653 (Free) ...
Akhirnya mari kita uji dalam produksi
Dan itu saja! Biasanya, di sinilah sebagian besar pengembang meninggalkan operasi mereka. Di masa mendatang, jika Anda membuat perubahan, Anda harus mengulangi langkah penerapan dan migrasi di atas. Anda bahkan dapat menjalankan tes jika Anda tidak terlambat untuk makan malam. Ini bagus sebagai titik awal, tetapi mari kita pikirkan metode ini sedikit lagi.
kelebihan
- Cepat untuk mengatur.
- Penyebarannya mudah.
Kontra
- Tidak KERING: Membutuhkan pengulangan langkah yang sama pada setiap perubahan.
- Tidak berversi: "Saya mengembalikan penerapan kemarin ke minggu lalu" tidak terlalu spesifik tiga minggu dari sekarang.
- Tidak tahan kode buruk: Anda tahu Anda seharusnya menjalankan tes, tetapi tidak ada yang melihat, jadi Anda mungkin mendorongnya meskipun terkadang tes rusak.
- Tidak buruk-aktor-bukti: Bagaimana jika pengembang yang tidak puas memutuskan untuk merusak aplikasi Anda dengan mendorong kode dengan pesan tentang bagaimana Anda tidak memesan cukup pizza untuk tim Anda?
- Tidak menskalakan: Mengizinkan setiap pengembang kemampuan untuk menerapkan akan memberi mereka akses tingkat produksi ke aplikasi, melanggar Prinsip Hak Istimewa Terkecil.
- Tidak ada lingkungan pementasan: Kesalahan khusus untuk lingkungan produksi tidak akan muncul hingga produksi.
Pipeline Penerapan Awal yang Sempurna
Saya akan mencoba sesuatu yang berbeda hari ini: Mari kita melakukan percakapan hipotetis. Saya akan memberikan suara kepada “Anda”, dan kita akan berbicara tentang bagaimana kita dapat meningkatkan aliran arus ini. Silakan, katakan sesuatu.
Katakan apa? Tunggu—aku bisa bicara?
Ya, itulah yang saya maksud tentang memberi Anda suara. Apa kabar?
Aku baik-baik saja. Ini terasa aneh
Saya mengerti, tetapi ikuti saja. Sekarang, mari kita bicara tentang pipa kita. Apa bagian yang paling menjengkelkan tentang menjalankan penerapan?
Itu mudah. Jumlah waktu yang saya buang. Apakah Anda pernah mencoba mendorong ke Heroku?
Ya, menonton dependensi Anda mengunduh dan aplikasi sedang dibangun sebagai bagian dari git push
itu mengerikan!
Saya tau? Ini gila. Saya berharap saya tidak perlu melakukan itu. Ada juga fakta bahwa saya harus menjalankan migrasi *setelah* penyebaran jadi saya harus menonton pertunjukan dan memeriksa untuk memastikan penyebaran saya berjalan melalui
Oke, Anda sebenarnya bisa menyelesaikan masalah terakhir itu dengan merantai dua perintah dengan &&
, seperti git push heroku master && heroku run rails db:migrate
, atau hanya membuat skrip bash dan memasukkannya ke dalam kode Anda, tapi tetap saja, jawaban yang bagus, waktu dan pengulangan adalah rasa sakit yang nyata.
Ya, itu benar-benar menyebalkan
Bagaimana jika saya memberi tahu Anda bahwa Anda dapat segera memperbaikinya dengan pipa CI/CD?
Apa sekarang? Apa itu?
CI/CD adalah singkatan dari continuous integration (CI) dan continuous delivery/deployment (CD). Cukup sulit bagi saya untuk memahami dengan tepat apa itu ketika saya memulai karena semua orang menggunakan istilah yang tidak jelas seperti "penggabungan pengembangan dan operasi", tetapi sederhananya:
- Integrasi Berkelanjutan: Memastikan semua kode Anda digabungkan di satu tempat. Minta tim Anda untuk menggunakan Git dan Anda akan menggunakan CI.
- Pengiriman Berkelanjutan: Memastikan kode Anda terus siap untuk dikirim. Artinya memproduksi versi read-to-mendistribusikan produk Anda dengan cepat.
- Penerapan Berkelanjutan: Mengambil produk dengan mulus dari pengiriman berkelanjutan dan hanya menerapkannya ke server Anda.
Oh, aku mengerti sekarang. Ini tentang membuat aplikasi saya menyebar secara ajaib ke dunia!
Artikel favorit saya yang menjelaskan CI/CD adalah oleh Atlassian di sini. Ini akan menjernihkan semua pertanyaan yang Anda miliki. Bagaimanapun, kembali ke masalah.
Ya, kembali ke itu. Bagaimana cara menghindari penerapan manual?
Menyiapkan Pipeline CI/CD untuk Di-deploy pada Push to master
Bagaimana jika saya memberi tahu Anda bahwa Anda dapat segera memperbaikinya dengan CI/CD? Anda dapat mendorong ke remote GitLab Anda ( origin
) dan komputer akan muncul untuk langsung mendorong kode Anda itu ke Heroku.
Tidak mungkin!
Ya cara! Mari kita kembali ke kode lagi.
Buat .gitlab-ci.yml
dengan konten berikut, toptal-pipeline
dengan nama aplikasi Heroku Anda:
image: ruby:2.4 before_script: - > : "${HEROKU_EMAIL:?Please set HEROKU_EMAIL in your CI/CD config vars}" - > : "${HEROKU_AUTH_TOKEN:?Please set HEROKU_AUTH_TOKEN in your CI/CD config vars}" - curl https://cli-assets.heroku.com/install-standalone.sh | sh - | cat >~/.netrc <<EOF machine api.heroku.com login $HEROKU_EMAIL password $HEROKU_AUTH_TOKEN machine git.heroku.com login $HEROKU_EMAIL password $HEROKU_AUTH_TOKEN EOF - chmod 600 ~/.netrc - git config --global user.email "[email protected]" - git config --global user.name "CI/CD" variables: APPNAME_PRODUCTION: toptal-pipeline deploy_to_production: stage: deploy environment: name: production url: https://$APPNAME_PRODUCTION.herokuapp.com/ script: - git remote add heroku https://git.heroku.com/$APPNAME_PRODUCTION.git - git push heroku master - heroku pg:backups:capture --app $APPNAME_PRODUCTION - heroku run rails db:migrate --app $APPNAME_PRODUCTION only: - master
Dorong ini, dan lihat itu gagal di halaman Pipeline proyek Anda. Itu karena tidak ada kunci otentikasi untuk akun Heroku Anda. Memperbaiki itu cukup mudah. Pertama, Anda memerlukan kunci API Heroku . Dapatkan dari halaman Kelola Akun, lalu tambahkan variabel rahasia berikut di pengaturan CI/CD repo GitLab Anda:
-
HEROKU_EMAIL
: Alamat email yang Anda gunakan untuk masuk ke Heroku -
HEROKU_AUTH_KEY
: Kunci yang kamu dapatkan dari Heroku
Ini akan menghasilkan GitLab yang berfungsi ke Heroku yang digunakan pada setiap push. Tentang apa yang terjadi:
- Setelah mendorong untuk menguasai
- Heroku CLI diinstal dan diautentikasi dalam sebuah wadah.
- Kode Anda didorong ke Heroku.
- Cadangan basis data Anda disimpan di Heroku.
- Migrasi dijalankan.
Sudah, Anda dapat melihat bahwa Anda tidak hanya menghemat waktu dengan mengotomatiskan semuanya ke git push
, Anda juga membuat cadangan database Anda di setiap penerapan! Jika terjadi kesalahan, Anda akan memiliki salinan database untuk dikembalikan.
Menciptakan Lingkungan Pementasan
Tapi tunggu, pertanyaan singkat, apa yang terjadi dengan masalah khusus produksi Anda? Bagaimana jika Anda mengalami bug aneh karena lingkungan pengembangan Anda terlalu berbeda dari produksi? Saya pernah mengalami beberapa masalah SQLite 3 dan PostgreSQL yang aneh ketika saya menjalankan migrasi. Spesifiknya menghindari saya, tapi itu sangat mungkin.

Saya benar-benar menggunakan PostgreSQL dalam pengembangan, saya tidak pernah tidak cocok dengan mesin database seperti itu, dan saya rajin memantau tumpukan saya untuk kemungkinan ketidakcocokan.
Yah, itu pekerjaan yang membosankan dan saya menghargai disiplin Anda. Secara pribadi, saya terlalu malas untuk melakukan itu. Namun, dapatkah Anda menjamin tingkat ketekunan itu untuk semua calon pengembang, kolaborator, atau kontributor di masa mendatang?
Errr— Ya, tidak. Anda punya saya di sana. Orang lain akan mengacaukannya. Apa maksudmu?
Maksud saya adalah, Anda membutuhkan lingkungan pementasan. Ini seperti produksi tetapi tidak. Lingkungan staging adalah tempat Anda berlatih penerapan ke produksi dan menangkap semua kesalahan Anda lebih awal. Lingkungan pementasan saya biasanya mencerminkan produksi, dan saya membuang salinan database produksi pada penyebaran pementasan untuk memastikan tidak ada kasus sudut sial yang mengacaukan migrasi saya. Dengan lingkungan pementasan, Anda dapat berhenti memperlakukan pengguna Anda seperti kelinci percobaan.
Ini masuk akal! Jadi bagaimana saya melakukan ini?
Di sinilah hal itu menjadi menarik. Saya suka menyebarkan master
langsung ke pementasan.
Tunggu, bukankah itu tempat kita menyebarkan produksi sekarang?
Ya, tapi sekarang kita akan menyebarkan ke pementasan sebagai gantinya.
Tetapi jika master
menyebarkan ke pementasan, bagaimana kami menyebarkan ke produksi?
Dengan menggunakan sesuatu yang seharusnya Anda lakukan bertahun-tahun yang lalu: Membuat versi kode kami dan mendorong tag Git.
Tag Git? Siapa yang menggunakan tag Git?! Ini mulai terdengar seperti banyak pekerjaan.
Memang benar, tapi untungnya, saya sudah melakukan semua pekerjaan itu dan Anda bisa membuang kode saya dan itu akan berhasil.
Pertama, tambahkan blok tentang penyebaran staging ke file .gitlab-ci.yml
Anda, saya telah membuat aplikasi Heroku baru bernama toptal-pipeline-staging
:
… variables: APPNAME_PRODUCTION: toptal-pipeline APPNAME_STAGING: toptal-pipeline-staging deploy_to_staging: stage: deploy environment: name: staging url: https://$APPNAME_STAGING.herokuapp.com/ script: - git remote add heroku https://git.heroku.com/$APPNAME_STAGING.git - git push heroku master - heroku pg:backups:capture --app $APPNAME_PRODUCTION - heroku pg:backups:restore `heroku pg:backups:url --app $APPNAME_PRODUCTION` --app $APPNAME_STAGING --confirm $APPNAME_STAGING - heroku run rails db:migrate --app $APPNAME_STAGING only: - master - tags ...
Kemudian ubah baris terakhir blok produksi Anda untuk dijalankan pada tag Git berversi semantik alih-alih cabang master:
deploy_to_production: ... only: - /^v(?'MAJOR'(?:0|(?:[1-9]\d*)))\.(?'MINOR'(?:0|(?:[1-9]\d*)))\.(?'PATCH'(?:0|(?:[1-9]\d*)))(?:-(?'prerelease'[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(?:\+(?'build'[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$/ # semver pattern above is adapted from https://github.com/semver/semver.org/issues/59#issuecomment-57884619
Menjalankan ini sekarang akan gagal karena GitLab cukup pintar untuk hanya mengizinkan akses cabang yang "dilindungi" ke variabel rahasia kami. Untuk menambahkan tag versi, buka halaman pengaturan repositori proyek GitLab Anda dan tambahkan v*
ke tag yang dilindungi.
Mari kita rekap apa yang terjadi sekarang:
- Setelah mendorong untuk menguasai, atau mendorong komit yang ditandai
- Heroku CLI diinstal dan diautentikasi dalam sebuah wadah.
- Kode Anda didorong ke Heroku.
- Cadangan produksi basis data Anda disimpan di Heroku.
- Cadangan dibuang di lingkungan pementasan Anda.
- Migrasi dijalankan pada database staging.
- Setelah mendorong komit yang diberi tag versi semantik
- Heroku CLI diinstal dan diautentikasi dalam sebuah wadah.
- Kode Anda didorong ke Heroku.
- Cadangan produksi basis data Anda disimpan di Heroku.
- Migrasi dijalankan di database produksi.
Apakah Anda merasa kuat sekarang? Saya merasa kuat. Saya ingat, pertama kali saya sampai sejauh ini, saya menelepon istri saya dan menjelaskan seluruh saluran pipa ini dengan sangat rinci. Dan dia bahkan tidak teknis. Saya sangat terkesan dengan diri saya sendiri, dan Anda juga seharusnya begitu! Pekerjaan bagus sampai sejauh ini!
Menguji Setiap Dorongan
Tapi masih ada lagi, karena komputer melakukan sesuatu untuk Anda, itu juga bisa menjalankan semua hal yang terlalu malas untuk Anda lakukan: Tes, kesalahan linting, hampir semua hal yang ingin Anda lakukan, dan jika salah satu dari ini gagal, mereka menang 't pindah ke penyebaran.
Saya suka memiliki ini di saluran saya, itu membuat ulasan kode saya menyenangkan. Jika permintaan penggabungan melewati semua pemeriksaan kode saya, itu layak untuk ditinjau.
Tambahkan blok test
:
test: stage: test variables: POSTGRES_USER: test POSTGRES_PASSSWORD: test-password POSTGRES_DB: test DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSSWORD}@postgres/${POSTGRES_DB} RAILS_ENV: test services: - postgres:alpine before_script: - curl -sL https://deb.nodesource.com/setup_8.x | bash - apt-get update -qq && apt-get install -yqq nodejs libpq-dev - curl -o- -L https://yarnpkg.com/install.sh | bash - source ~/.bashrc - yarn - gem install bundler --no-ri --no-rdoc - bundle install -j $(nproc) --path vendor - bundle exec rake db:setup RAILS_ENV=test script: - bundle exec rake spec - bundle exec rubocop
Mari kita rekap apa yang terjadi sekarang:
- Atas setiap dorongan, atau gabungkan permintaan
- Ruby dan Node diatur dalam sebuah wadah.
- Dependensi dipasang.
- Aplikasi ini diuji.
- Setelah mendorong untuk menguasai, atau mendorong komit yang ditandai, dan hanya jika semua tes lulus
- Heroku CLI diinstal dan diautentikasi dalam sebuah wadah.
- Kode Anda didorong ke Heroku.
- Cadangan produksi basis data Anda disimpan di Heroku.
- Cadangan dibuang di lingkungan pementasan Anda.
- Migrasi dijalankan pada database staging.
- Setelah mendorong komit yang diberi tag versi semantik, dan hanya jika semua tes lulus
- Heroku CLI diinstal dan diautentikasi dalam sebuah wadah.
- Kode Anda didorong ke Heroku.
- Cadangan produksi basis data Anda disimpan di Heroku.
- Migrasi dijalankan di database produksi.
Mundur selangkah dan kagumi tingkat otomatisasi yang telah Anda capai. Mulai sekarang, yang harus Anda lakukan hanyalah menulis kode dan push. Uji aplikasi Anda secara manual dalam staging jika Anda menginginkannya, dan ketika Anda merasa cukup percaya diri untuk meluncurkannya ke seluruh dunia, beri tag dengan versi semantik!
Versi Semantik Otomatis
Ya, itu sempurna, tapi ada sesuatu yang hilang. Saya tidak suka mencari versi terakhir aplikasi dan secara eksplisit menandainya. Itu membutuhkan banyak perintah dan mengalihkan perhatian saya selama beberapa detik.
Oke, Bung, berhenti! Cukup. Anda hanya merekayasanya sekarang. Ini berhasil, itu brilian, jangan merusak hal yang baik dengan melampaui batas.
Oke, saya punya alasan bagus untuk melakukan apa yang akan saya lakukan.
Berdoalah, beri aku pencerahan.
Aku dulu seperti kamu. Saya senang dengan pengaturan ini, tetapi kemudian saya mengacaukannya. git tag
mencantumkan tag dalam urutan abjad, v0.0.11
di atas v0.0.2
. Saya pernah secara tidak sengaja menandai rilis dan terus melakukannya selama sekitar setengah lusin rilis sampai saya melihat kesalahan saya. Saat itulah saya memutuskan untuk mengotomatisasi ini juga.
Baiklah, kita lanjut lagi
Oke, jadi, untungnya, kami memiliki kekuatan npm yang kami miliki, jadi saya menemukan paket yang sesuai: Jalankan yarn add --dev standard-version
dan tambahkan yang berikut ke file package.json
Anda:
"scripts": { "release": "standard-version", "major": "yarn release --release-as major", "minor": "yarn release --release-as minor", "patch": "yarn release --release-as patch" },
Sekarang Anda perlu melakukan satu hal terakhir, konfigurasikan Git untuk mendorong tag secara default. Saat ini, Anda perlu menjalankan git push --tags
untuk mendorong tag ke atas, tetapi secara otomatis melakukannya pada git push
biasa semudah menjalankan git config --global push.followTags true
.
Untuk menggunakan pipeline baru Anda, kapan pun Anda ingin membuat peluncuran rilis:
-
yarn patch
untuk rilis tambalan -
yarn minor
untuk rilis kecil -
yarn major
untuk rilis utama
Jika Anda tidak yakin tentang arti kata "mayor", "minor", dan "patch", baca lebih lanjut tentang ini di situs versi semantik.
Sekarang setelah Anda akhirnya menyelesaikan pipeline Anda, mari rekap cara menggunakannya!
- Tulis kode.
- Komit dan dorong untuk menguji dan menyebarkannya ke pementasan.
- Gunakan
yarn patch
untuk menandai rilis tambalan. -
git push
untuk mendorongnya ke produksi.
Ringkasan dan Langkah Selanjutnya
Saya baru saja menggores permukaan dari apa yang mungkin dengan pipa CI/CD. Ini adalah contoh yang cukup sederhana. Anda dapat melakukan lebih banyak hal dengan menukar Heroku dengan Kubernetes. Jika Anda memutuskan untuk menggunakan GitLab CI, baca dokumen yaml karena masih banyak lagi yang dapat Anda lakukan dengan menyimpan file di antara penerapan, atau menyimpan artefak!
Perubahan besar lainnya yang dapat Anda lakukan pada pipeline ini adalah memperkenalkan pemicu eksternal untuk menjalankan versi semantik dan merilisnya. Saat ini, ChatOps adalah bagian dari paket berbayar mereka, dan saya harap mereka merilisnya ke paket gratis. Tapi bayangkan bisa memicu gambar berikutnya melalui satu perintah Slack!
Akhirnya, saat aplikasi Anda mulai menjadi kompleks dan memerlukan dependensi tingkat sistem, Anda mungkin perlu menggunakan wadah. Ketika itu terjadi, lihat panduan kami: Memulai Docker: Menyederhanakan Devops .
Aplikasi contoh ini benar-benar aktif, dan Anda dapat menemukan kode sumbernya di sini.