Bayangkan harus mengetikkan perintah panjang berulang kali untuk tugas-tugas seperti membangun dan menjalankan container Docker. Ini akan membosankan dan memakan waktu.
Namun, dengan mendefinisikan skrip npm, kita dapat dengan mudah memicu tugas-tugas ini dengan perintah yang singkat dan jelas. Ini menyederhanakan alur kerja kami dan mengurangi upaya yang diperlukan untuk menyelesaikan tugas-tugas umum sebagai pengembang, menjadikan proses pengembangan lebih efisien dan menyenangkan.
Skrip Npm memberikan pendekatan yang nyaman dan efisien untuk mengotomatiskan tugas yang berulang, meningkatkan produktivitas, dan memungkinkan kami fokus pada bisnis inti kami.
Dalam panduan ini, kita akan membuat container buruh pelabuhan sederhana dan bereksperimen dengan berbagai skrip npm untuk melihat cara mengoptimalkan proses pembangunan.

Mulai

Mari kita siapkan repositorinya. Kami kemudian akan bereksperimen dengan beberapa skrip npm untuk memudahkan pengembangan.
Di folder baru, jalankan perintah berikut:

npm init -y

Bendera -y berarti 'ya' atau 'ya untuk semua'. Saat Anda menggunakannya, ini memungkinkan Anda untuk menginisialisasi file package.json baru dengan semua nilai default tanpa perintah pengguna apa pun. Ini berarti Anda secara otomatis menerima semua pengaturan default untuk konfigurasi package.json Anda.
Sekarang, mari instal Express sebagai dependensi. Kita akan membutuhkan ini di file server.js yang akan kita buat sebelumnya.

npm i express

Sekarang buat file baru —server.js di root repositori ini. Untuk menjaga fokus panduan ini pada skrip npm, kita akan membuat aplikasi dasar Node.js menggunakan kerangka Express untuk membuat server HTTP sederhana yang melakukan hal berikut:

  1. Mengimpor modul Express dan membuat aplikasi Express.
  2. Setel port server ke port 4005 . Kita juga dapat menggunakan variabel lingkungan PORT menggunakan process.env atau defaultnya ke 4005.
  3. Mendefinisikan pesan yang akan dikirim sebagai respons kepada klien ketika mereka mengakses jalur root ('/').
  4. Menyiapkan rute untuk menangani permintaan HTTP GET ke jalur root. Saat diakses, ia mencatat pesan ke konsol server dan mengirimkan pesan yang ditentukan sebagai respons.
  5. Memulai server pada port yang ditentukan, dan setelah server dimulai, ia mencatat pesan yang ditentukan ke konsol.

server.js akan terlihat seperti ini:

const express = require('express');
const app = express();
const port = process.env.PORT || 4005;
let runningMessage = 'Server is running on port ' + port;

app.get('/', (req, res) => {
    console.log('API was requested');
    res.send(runningMessage);
    }
);

const server = app.listen(port, () => {
    console.log(runningMessage);
});

Sekarang mari kita buat Dockerfile yang menyiapkan image Docker untuk aplikasi kita. Ini menginstal dependensi aplikasi, menyalin kode aplikasi, dan menentukan perintah default untuk memulai aplikasi Node.js menggunakan node server.js sambil mengekspos port 4005 di dalam container. Untuk menjalankan aplikasi, kita perlu membuat image dari Dockerfile ini, lalu membuat dan memulai container berdasarkan image tersebut. Di direktori root, buat Dockerfile:

FROM node:18.10.0

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

# Expose port
EXPOSE 4005

# Run app
CMD [ "node", "server.js" ]

Buat .dockerignore di folder root:

node_modules
npm-debug.log

File .dockerignore diperlukan untuk mengontrol konten image Docker, mengurangi ukurannya, meningkatkan keamanan, dan memastikan bahwa informasi sensitif tidak terekspos secara tidak sengaja.
Sekarang semuanya sudah diatur, mari tambahkan dua skrip dasar di package.json mengajukan. Di bawah objek scripts, tambahkan skrip npm berikut:

"docker:build": "docker build -t npm_docker .",
"docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",

Bendera -t pada perintah docker:build digunakan untuk menandai gambar dengan nama (npm_docker dalam kasus ini). Nama ini akan digunakan untuk mereferensikan gambar saat menjalankan container berdasarkan gambar tersebut.

Pada perintah docker:run, -p 4005:4005maps port 4005 dari host ke port 4005 di container. Hal ini memungkinkan lalu lintas dikirim dari mesin host ke aplikasi yang berjalan di dalam container. -d menunjukkan bahwa container berjalan dalam mode terpisah, artinya container akan berjalan di latar belakang sebagai daemon. Flag --name memberi nama pada container (npm_d), yang nantinya dapat digunakan untuk mengelola dan berinteraksi dengan container.

Konvensi penamaan

Di sini kami menggunakan konvensi penamaan seperti category:name karena memberikan kejelasan, pengorganisasian, dan konsistensi dalam file package.json.

Dalam konteks docker:build dan docker:run , ini menandakan maksud dan hubungan skrip dengan operasi Docker. Awalan docker: dengan jelas menunjukkan bahwa skrip ini terkait dengan tugas Docker.

Konvensi ini membantu menghindari konflik penamaan, meningkatkan keterbacaan, dan memudahkan pengelompokan dan pelaksanaan skrip terkait. Dengan mengikuti konvensi ini, pengembang dapat dengan mudah memahami dan mengelola tugas pembuatan dan menjalankan Docker dalam proyek.

Untuk mengetahui lebih banyak tentang konvensi penamaan, baca ini: package-json-conventions.

Tugas Pengembangan Docker

Tantangan muncul dengan Docker ketika kita perlu memperbarui kode aplikasi dalam container yang sedang berjalan. Tidak seperti pengaturan pengembangan tradisional, kita tidak bisa begitu saja membangun kembali image Docker dan menjalankannya kembali karena container yang ada sudah berjalan.

Dengan Docker, pertama-tama kita harus menghentikan jalannya container, lalu menghapusnya, lalu membangun kembali dan menjalankan kembali container baru menggunakan image baru setiap kali kita membuat perubahan kode sumber pada aplikasi kita.

Mari tambahkan dua skrip lagi untuk ini. kami akan menamainya docker:stop dan docker:remove agar tetap sejalan dengan konvensi penamaan kami.
Sekarang perbaruiscripts di package.json sebagai berikut:

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

Sekarang ketika Anda membuat perubahan apa pun di server.js, Anda dapat membuat penampung yang baru diperbarui, tetapi Anda tidak dapat menjalankannya karena penampung dengan nama yang sama sudah berjalan. Oleh karena itu Anda perlu menjalankan docker:stop dan docker:remove sebelum menjalankan perintah docker:run.

Mengotomatiskan Tugas Pengembangan Docker

Proses menghentikan container yang sedang berjalan, menghapusnya, membangun kembali image Docker, dan membuat container baru setiap kali kita melakukan perubahan kode bukanlah alur kerja yang paling efisien. Namun, kami memiliki keuntungan karena Docker memberikan argumen yang memungkinkan kami untuk secara aktif mendengarkan perubahan kode dan secara otomatis memperbarui container tanpa melalui langkah manual.
Jadi, meskipun skrip NPM bukan merupakan faktor pembatas dalam skenario ini, Kemampuan Docker untuk secara aktif mendengarkan perubahan kode dan memetakannya ke dalam container memberi kita cara yang lebih efisien dan nyaman untuk mengembangkan dan menguji aplikasi kita di lingkungan Docker.

Inilah saatnya argumen lain yang tersedia melalui alat Docker CLI yang disebut “pemasangan volume” dapat membantu.

Mari segera perbarui scripts di package.json dan lihat apa fungsi pemasangan volume.

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",
    "docker:run:dev": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

Script di docker:run:dev hampir mirip dengan script di docker:run kecuali argumen -v. Opsi ini memasang direktori kerja saat ini (%cd%) dari host ke direktori /usr/src/app di dalam penampung.

CATATAN: Jalur ke sisi kiri titik dua (:) adalah jalur menuju lokasi kode sumber Anda. Pada mesin Windows, kita dapat menggunakan %cd% , dan pada mesin Linux, kita dapat menggunakan $(pwd) untuk mendapatkan direktori kerja.
Jalur ke sisi kanan titik dua (:) adalah jalur direktori di dalam wadah Docker tempat Anda ingin memasang atau memetakan kode sumber Anda. Proses ini melapisi kode sumber lokal Anda dari mesin host ke dalam wadah, memungkinkan pembaruan dinamis setiap kali Anda membuat perubahan pada kode Anda.

Saat Anda menggunakan -v untuk memasang kode sumber lokal ke dalam penampung, hal ini memungkinkan perubahan diterapkan di dalam penampung tanpa membangunnya kembali. Namun, ini hanya membuat kode Anda dapat diakses di dalam penampung; itu tidak mengatasi masalah pendeteksian dan memulai ulang server Node.js secara otomatis setiap kali terjadi perubahan pada kode Anda. Untuk mengatasi masalah ini, kami akan menggunakan nodemon .

Nodemon adalah utilitas yang memantau aplikasi Node.js Anda untuk melihat perubahan file. Ini secara otomatis memulai ulang server Node.js ketika mendeteksi adanya modifikasi pada basis kode Anda. Fitur ini sangat penting untuk proses pengembangan karena ini akan menyelamatkan Anda dari kesulitan menghentikan dan memulai ulang server secara manual setiap kali Anda melakukan perubahan.

Sekarang, di Dockerfile kita perlu membuat dua perubahan:

  1. Untuk memastikan Nodemon tersedia di dalam container, kami menginstalnya secara global. Berbeda dengan pengembangan, di mana Nodemon biasanya diinstal sebagai dependensi dev, di sini kita memerlukannya untuk sistem mirip produksi di dalam container. Dengan menginstalnya secara global, Nodemon menjadi alat baris perintah yang dapat diakses di seluruh container. Dengan cara ini, kita dapat menggunakan Nodemon untuk memulai dan memantau aplikasi kita terhadap perubahan dalam lingkungan seperti produksi.
  2. Untuk memulai aplikasi kita menggunakan Nodemon di dalam container, kita akan mengganti perintah node dengan nodemon untuk menjalankan server.js. Selain itu, kami akan menambahkan argumen -L untuk menunjukkan mode tontonan lama karena kami bekerja dalam sebuah container.

Dockerfile yang diperbarui akan terlihat seperti ini:

FROM node:18.10.0

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

RUN npm install -g nodemon

# Bundle app source
COPY . .

# Expose port
EXPOSE 4005

# Run app
CMD [ "nodemon", "-L", "server.js" ]

Dengan perubahan ini, Dockerfile kami sekarang sudah diatur dengan benar untuk menggunakan Nodemon untuk memulai aplikasi dan memantau perubahan kode.

Membungkus

Sebelum menjalankan docker:run:dev kita perlu memastikan bahwa tidak ada container yang berjalan dengan nama yang sama. Kita dapat menjalankan skrip docker:stop dan docker:remove yang kita definisikan di atas dan kemudian docker:build sebelum menjalankan docker:run:dev .

Di sinilah kita dapat menggunakan operator && dan &.
&& berfungsi seperti logika AND. Perintah pertama dijalankan, dan jika berhasil diselesaikan (mengembalikan kode keluar 0), barulah perintah kedua akan dijalankan. Perilaku ini memastikan bahwa perintah berikutnya dijalankan secara kondisional berdasarkan keberhasilan perintah sebelumnya. Ini memungkinkan Anda membuat urutan perintah yang setiap langkahnya bergantung pada keberhasilan penyelesaian langkah sebelumnya.
Menggunakan & dalam skrip npm memulai eksekusi paralel, memungkinkan perintah kedua berjalan secara independen di latar belakang, meskipun perintah pertama perintah masih dalam proses atau menemui kesalahan.

Sekarang, dengan pengetahuan ini, mari kita coba memodifikasi scripts di package.json :

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run:dev": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "docker:run": "npm run docker:stop & npm run docker:remove & npm run docker:build && npm run docker:run:dev"
  },
...

Di sini, kami menggunakan & antara npm run docker:stop , npm run docker:remove dan npm run docker:build . Hal ini karena, meskipun baru dijalankan, container dengan nama yang diberikan ( npm_d dalam kasus kami) tidak ada, maka rangkaian perintah tidak boleh berhenti, dan proses build harus dilanjutkan.
Namun, && digunakan antara npm run docker:build dan npm:docker:run . Hal ini karena jika, karena alasan apa pun, proses pembangunan gagal, maka perintah run tidak boleh dijalankan, dan rantai perintah berakhir.

Sekarang mari kita coba menyederhanakannya lebih jauh lagi. Kami akan menggunakan paket npm-run-all untuk menjalankan skrip npm secara berurutan. Instal npm-run all menggunakan perintah berikut:

npm i npm-run-all

Sekarang amati perubahan pada scripts dari package.json :

...
"scripts": {
    "docker:stop": "docker container stop npm_d || true",
    "docker:remove": "docker container rm npm_d || true",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "docker:run:dev": "npm-run-all docker:*"
  },
...

Perhatikan bagaimana kita menggunakan docker:* di docker:run:dev . npm-run-all menyediakan cara serbaguna dan ampuh untuk mengelola dan mengontrol eksekusi skrip npm, mengurangi kompleksitas dan meningkatkan efisiensi proses pembangunan Anda.

Perintah diatas berarti semua script yang diawali dengan awalan docker: akan dijalankan secara berurutan. Di sinilah konvensi penamaan kami berguna.
Di sini, || true memastikan bahwa meskipun docker:stop dan docker:remove memunculkan kesalahan, rantai perintah tidak boleh berhenti, dan eksekusi berpindah ke perintah build.

Dan begitulah, cukup menjalankan docker:run:dev saja sudah membuat Anda siap untuk memulai. Dengan menggunakan skrip npm, Anda dapat dengan mudah mengelola container Docker dan tugas berulang lainnya, sehingga Anda dapat lebih fokus pada bisnis inti dan mengurangi pengaturan manual.

Konten lainnya di PlainEnglish.io.

Daftar ke buletin mingguan gratis kami. Ikuti kami di "Twitter", "LinkedIn", "YouTube", dan "Discord" .