Dockerfile Mastery: Dockerfile ලියන්න | Sinhala Docker Tutorial

ආයුබෝවන් යාලුවනේ! කොහොමද ඉතින්? අද අපි කතා කරන්න යන්නේ නූතන Software Development වලදී නැතුවම බැරි දෙයක් ගැන – ඒ තමයි Docker සහ Dockerfile Mastery. Docker කියන්නේ අපේ applications build, ship, run කරන්න උදව් වෙන platform එකක්. ඒත්, Docker වල full potential එක ගන්න නම්, හරියටම Dockerfile එකක් ලියන්න දැනගෙන ඉන්න එක අත්යවශ්යයි. ලංකාවේ අපි වගේ developersලට මේක ගොඩක් වැදගත් වෙන්නේ, production environment එකට යනකොට අපේ applicationsලට stable, reliable run වෙන්න ඕන නිසා.
මේ tutorial එකෙන් අපි Dockerfile එකක් මූලිකවම ලියන්නේ කොහොමද, ඒකට අවශ්ය directives මොනවද, multi-stage builds වගේ advanced concepts මොනවද, .dockerignore files මොකටද, හොඳම practices මොනවද, වගේම security ගැනත් ඉගෙන ගන්නවා. ඉතින්, තවත් පරක්කු නොවී අපි වැඩේට බහිමු!
Dockerfile කියන්නේ මොකක්ද?
සරලවම කිව්වොත්, Dockerfile එකක් කියන්නේ plain text file එකක්. මේකේ අපේ Docker image එකක් හදන්න අවශ්ය steps, instructions ටික ලියලා තියෙනවා. අපි docker build
command එක run කරනකොට, Docker engine එක මේ Dockerfile එක කියවලා එකින් එක instructions execute කරලා අපේ application එක run කරන්න පුළුවන් Docker image එකක් හදනවා. මේක හරියට application එකක් install කරනකොට අපි අනුගමනය කරන manual steps ටික automatic කරන්න ලියන script එකක් වගේ.
ඇයි Dockerfile Mastery අපිට වැදගත් වෙන්නේ?
- Efficiency (කාර්යක්ෂමතාවය): හොඳින් ලියූ Dockerfile එකක් නිසා images ඉක්මනට build වෙනවා, file size අඩු වෙනවා, resources efficient විදියට භාවිතා වෙනවා.
- Reliability (විශ්වාසනීයත්වය): හරියට ලියපු Dockerfile එකක් නිසා අපේ application එක ඕනෑම පරිසරයක එකම විදියට run වෙනවා. "It works on my machine" කියන ප්රශ්නය මග හැරෙනවා.
- Security (ආරක්ෂාව): Best practices අනුගමනය කිරීමෙන් අපේ images වල security vulnerabilities අඩු කරගන්න පුළුවන්.
- Maintainability (නඩත්තු කිරීම): පැහැදිලි, සංවිධානාත්මක Dockerfiles නඩත්තු කරන්න සහ update කරන්න පහසුයි.
මූලික Dockerfile Directives
Dockerfile එකක් ලියන්න අවශ්ය මූලික instructions ටික අපි දැන් බලමු.
FROM
: Base Image එක තෝරාගැනීම
මේක තමයි Dockerfile එකක පළමු instruction එක. අපේ image එක හදන්න පාවිච්චි කරන base image එක මේකෙන් specify කරනවා. Base image එකේ අපිට අවශ්ය operating system (Ubuntu, Alpine), runtime (Node.js, Python, Java) වගේ දේවල් අඩංගු වෙනවා.
FROM node:16-alpine
# OR
FROM python:3.9-slim-buster
# OR
FROM openjdk:11-jre-slim
alpine
වගේ ඒවා ගොඩක් lightweight නිසා ගොඩක් වෙලාවට ඒවා භාවිතා කරනවා.
RUN
: Commands execute කිරීම
Image එක build කරනකොට execute කරන්න අවශ්ය commands මේකෙන් දෙනවා. Software packages install කරන්න, folders හදන්න, files download කරන්න වගේ දේවල් වලට මේක පාවිච්චි කරනවා.
FROM node:16-alpine
RUN apk add --no-cache git
RUN mkdir /app
WORKDIR /app
RUN npm install
Tip: RUN
commands ගොඩක් එකතු කරනකොට &&
වලින් එක command එකක් විදියට ලියන එක හොඳයි. මොකද Docker build වෙනකොට හැම RUN
command එකකටම අලුත් layer එකක් හැදෙනවා. Layers වැඩි වෙනකොට image size එක වැඩි වෙනවා.
FROM node:16-alpine
RUN apk add --no-cache git \
&& mkdir /app \
&& echo "Hello World" > /app/hello.txt
WORKDIR
: Working Directory එක සකස් කිරීම
RUN
, CMD
, ENTRYPOINT
, COPY
, ADD
වගේ instructions වලට default directory එක මේකෙන් define කරනවා. අපිට හැම වෙලේම full path එක දෙන්න අවශ්ය වෙන්නේ නෑ.
FROM node:16-alpine
WORKDIR /app
COPY . .
# දැන් COPY command එකෙන් host එකේ current directory එකේ තියෙන files /app එකට copy වෙනවා.
COPY
සහ ADD
: Files Image එකට copy කිරීම
Files සහ directories අපේ host machine එකේ ඉඳන් Docker image එක ඇතුලට copy කරන්න මේ instructions පාවිච්චි කරනවා.
COPY
: Local files සහ directories copy කරන්න. Symbolic links handle කරන්න පුළුවන්. මෙය වඩාත් නිර්දේශිතයි.ADD
:COPY
වගේමයි, ඒත් මේකට URLs වලින් files download කරන්න පුළුවන්, වගේම compressed files (tar, gzip, bzip2) automatic extract කරන්නත් පුළුවන්. මේ feature එක නිසා security risks වැඩි වෙන්න පුළුවන්, ඒ වගේම image size එකත් වැඩි වෙන්න පුළුවන්. ඒ නිසාCOPY
භාවිතා කිරීම වඩාත් සුදුසුයි.
FROM node:16-alpine
WORKDIR /app
COPY package*.json . # host එකේ තියෙන package.json සහ package-lock.json copy කරනවා
RUN npm install
COPY . .
CMD ["node", "server.js"]
EXPOSE
: Ports expose කිරීම
Container එක listen කරන port එක මේකෙන් Docker platform එකට දැනුම් දෙනවා. මේක documentation purpose එකක් විතරයි, port එක publish වෙන්නේ නෑ. publish කරන්න docker run -p
command එක භාවිතා කරන්න ඕන.
FROM node:16-alpine
# ... application code ...
EXPOSE 3000 # මේ application එක 3000 port එකෙන් listen කරන බව කියනවා
CMD
සහ ENTRYPOINT
: Container එක start කරන command එක
මේ දෙකෙන් තමයි container එක start වෙනකොට execute වෙන්න ඕන command එක specify කරන්නේ.
CMD
: Container එක run වෙනකොට execute වෙන default command එක සපයනවා. Dockerfile එකකCMD
instruction එකක් විතරයි තියෙන්න පුළුවන්.docker run
command එකෙන් වෙනත් command එකක් දුන්නොත් මේක override වෙනවා.ENTRYPOINT
: Container එකේ ප්රධාන command එක set කරනවා.CMD
වගේ override වෙන්නේ නෑ.ENTRYPOINT
එකCMD
එක්ක එකට භාවිතා කරන්න පුළුවන්, ඒ වෙලාවටCMD
එකENTRYPOINT
එකට arguments විදියට pass වෙනවා.
උදාහරණ:
CMD
පමණක්:
FROM ubuntu
CMD ["echo", "Hello from Ubuntu!"]
Run: docker run my-image
-> Output: Hello from Ubuntu!
Override: docker run my-image echo "New command!"
-> Output: New command!
ENTRYPOINT
සහ CMD
එකට:
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]
CMD ["World!"]
Run: docker run my-image
-> Output: Hello World!
(CMD
එක ENTRYPOINT
එකට argument එකක් විදියට යනවා)
Override CMD
: docker run my-image "Sri Lanka!"
-> Output: Hello Sri Lanka!
ENTRYPOINT
එක application එකේ executable එක විදියට තියලා, CMD
එක default arguments විදියට දෙන එක හොඳ practice එකක්.
සරල Node.js Application එකක් සඳහා Dockerfile එකක්:
අපි Node.js web server එකක් Dockerize කරමු.
server.js
file එක:
const http = require('http');
const hostname = '0.0.0.0';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from Docker, Sri Lanka!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
package.json
file එක:
{
"name": "docker-node-app",
"version": "1.0.0",
"description": "A simple Node.js app for Docker tutorial",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
මෙන්න මේකට ගැලපෙන Dockerfile එක:
# 1. Base image එක තෝරනවා
FROM node:16-alpine
# 2. Working directory එක හදනවා
WORKDIR /app
# 3. package.json සහ package-lock.json files copy කරනවා
# මේකෙන් npm install එක ඉක්මන් කරනවා මොකද මේ files වෙනස් නොවෙනකම් layer එක cache වෙනවා.
COPY package*.json .
# 4. Dependencies install කරනවා
RUN npm install
# 5. Application files ටික copy කරනවා
COPY . .
# 6. Container එක listen කරන port එක expose කරනවා
EXPOSE 3000
# 7. Container එක start කරන command එක define කරනවා
CMD ["npm", "start"]
මේක build කරන්න: docker build -t my-node-app .
Run කරන්න: docker run -p 80:3000 my-node-app
දැන් browser එකේ http://localhost/
එකට ගියාම අපේ message එක පෙන්වයි.
Advanced Dockerfile Techniques
.dockerignore
File එකේ වැදගත්කම
අපි COPY . .
වගේ command එකක් දෙනකොට, Docker build context එකේ තියෙන හැම file එකක්ම image එකට copy වෙනවා. මේකෙන් image size එක වැඩි වෙන්න පුළුවන්, වගේම sensitive files image එකට යන්නත් පුළුවන් (උදා: .git
, node_modules
folder එක local machine එකේ තියෙනවා නම්). .dockerignore
file එක හරියට .gitignore
වගේ වැඩ කරන්නේ. මේකේ specify කරන files සහ folders build context එකට add වෙන්නේ නෑ.
.dockerignore
example:
node_modules
npm-debug.log
.git
.gitignore
.env
docker-compose.yml
README.md
Dockerfile
මේකෙන් අපි අනවශ්ය files image එකට copy වීම වළක්වනවා.
Multi-stage Builds: Image Size අඩු කරගැනීම
මේක Dockerfile Mastery වල තියෙන සුපිරිම feature එකක්! අපේ applications build කරනකොට dependencies ගොඩක් install කරන්න වෙනවා, build tools ඕන වෙනවා. ඒත් application එක run වෙන්න ඒ හැම දෙයක්ම අවශ්ය වෙන්නේ නෑ. Multi-stage builds වලින් පුළුවන් build environment එකයි, runtime environment එකයි වෙන් කරන්න. මේකෙන් image size එක පුදුමාකාර විදියට අඩු කරගන්න පුළුවන්. ඒ වගේම security risks අඩු වෙනවා, build process එක simplify වෙනවා.
උදාහරණයක්: Simple Go application එකක් සඳහා multi-stage build එකක්.
main.go
file එක:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Go in Docker, Sri Lanka!")
})
fmt.Println("Server starting on port 8080...")
http.ListenAndServe(":8080", nil)
}
Multi-stage Dockerfile:
# Stage 1: Build stage (build environment එක)
FROM golang:1.17-alpine AS builder
WORKDIR /app
COPY main.go .
# Go application එක compile කරනවා
RUN go mod init example.com/my-app # if you have modules
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/my-app
# Stage 2: Run stage (runtime environment එක)
# මේක ගොඩක් lightweight image එකක්
FROM alpine:latest
WORKDIR /app
# Build stage එකෙන් compile කරපු executable file එක විතරක් copy කරනවා
COPY --from=builder /app/my-app .
EXPOSE 8080
CMD ["./my-app"]
මේ Dockerfile එක build කලාම, අවසාන image එකේ තියෙන්නේ Alpine base image එකයි, අපේ compiled Go executable එකයි විතරයි. Go compiler එක, build tools කිසිවක් අවසාන image එකේ නෑ. මේකෙන් image size එක විශාල වශයෙන් අඩු වෙනවා.
ENV
: Environment Variables සකස් කිරීම
Container එක ඇතුලේ environment variables set කරන්න ENV
instruction එක පාවිච්චි කරනවා. මේක configuration values set කරන්න, paths specify කරන්න වගේ දේවල් වලට වැදගත් වෙනවා.
FROM node:16-alpine
ENV NODE_ENV=production
ENV PORT=3000
# ...
CMD ["node", "server.js"]
USER
: Non-root User එකක් ලෙස run කිරීම
Default එකෙන් containers root user එකක් විදියට run වෙන්නේ. Security wise මේක එච්චර හොඳ දෙයක් නෙවෙයි. Container එකේ අවම privileges තියෙන non-root user කෙනෙක් විදියට run කරන එක හොඳ practice එකක්.
FROM node:16-alpine
# ...
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# ...
CMD ["node", "server.js"]
HEALTHCHECK
: Container Health check කිරීම
Container එකේ health status එක check කරන්න මේක පාවිච්චි කරනවා. Container එක වැඩ කරනවද කියලා Docker engine එකට මේකෙන් දැනුම් දෙනවා. Orchestration tools (Kubernetes) වලදී මේක ගොඩක් වැදගත්.
FROM node:16-alpine
# ...
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl --fail http://localhost:3000/ || exit 1
# ...
මේකෙන් සෑම තත්පර 30කට වරක්ම http://localhost:3000/
එකට curl
request එකක් යවනවා. Fail උනොත් container එක unhealthy විදියට සලකනවා.
Dockerfile Best Practices සහ Security
හොඳ Dockerfile එකක් කියන්නේ efficient විතරක් නෙවෙයි, secure එකක් වෙන්නත් ඕන. මෙන්න අපිට අනුගමනය කරන්න පුළුවන් තවත් tips ටිකක්:
- අනවශ්ය Packages Install කිරීමෙන් වළකින්න: Production image එකකට build tools, debuggers වගේ අනවශ්ය දේවල් install කරන්න එපා. Multi-stage builds මේකට හොඳ විසඳුමක්.
- Non-root User කෙනෙක් ලෙස Run කරන්න: Container එක root user එකක් විදියට run කිරීමෙන් security risks වැඩි වෙනවා.
USER
instruction එක පාවිච්චි කරලා non-root user කෙනෙක් විදියට run කරන්න. - Versions Pin කරන්න: Base images, packages වල versions හැමවිටම pin කරන්න (උදා:
FROM node:16-alpine
මිසක්FROM node:latest
නෙවෙයි). මේකෙන් builds predictable වෙනවා. නැතිනම්latest
එක හැම වෙලාවෙම වෙනස් වෙන්න පුළුවන්. - Secrets Manage කරන්න: Passwords, API keys වගේ sensitive data Dockerfile එකේ හෝ image එකේ තැන්පත් කරන්න එපා. Environment variables විදියට pass කරනවා නම්, ඒවා
docker run -e
හෝ Docker secrets/Kubernetes secrets වගේ mechanisms වලින් manage කරන්න. - Security Scanning Tools භාවිතා කරන්න: Trivy, Snyk Container, Clair වගේ tools වලින් අපේ Docker images scan කරලා security vulnerabilities තියෙනවද කියලා බලන්න. මේක CI/CD pipeline එකට integrate කරන එක ඉතා වැදගත්.
Layer Caching Optimize කරන්න: Docker build එකේදී instructions layers විදියට cache වෙනවා. නිතරම වෙනස් වන commands (උදා: COPY . .
) Dockerfile එකේ අන්තිම හරියට දාන්න. නිතර වෙනස් නොවන commands (උදා: RUN npm install
) උඩින් දාන්න. මේකෙන් build time එක අඩු වෙනවා.
FROM node:16-alpine
WORKDIR /app
COPY package*.json . # මේක නිතර වෙනස් වෙන්නේ නෑ -> cache වෙන්න හොඳයි
RUN npm install # මේකත් නිතර වෙනස් වෙන්නේ නෑ -> cache වෙන්න හොඳයි
COPY . . # මේක නිතර වෙනස් වෙනවා -> අන්තිම හරියට දාන්න
CMD ["npm", "start"]
Smallest Base Image එකක් තෝරාගන්න: alpine
වගේ lightweight images පාවිච්චි කරන්න. මේවායේ අනවශ්ය packages අඩුයි, ඒ නිසා image size එකත් අඩුයි, attack surface එකත් අඩුයි.
FROM alpine:latest # ඉතා කුඩා image එකක්
FROM debian:slim # Debian වල slim version එක
FROM node:16-alpine # Node.js සඳහා
අවසන් වචනය
ඉතින් යාලුවනේ, Dockerfile Mastery කියන්නේ Docker වල full potential එක ගන්න අත්යවශ්ය දෙයක්. මේ tutorial එකෙන් අපි Dockerfile එකක් ලියන්න අවශ්ය මූලික directives ටික, multi-stage builds වගේ advanced techniques, .dockerignore
එකේ වැදගත්කම, වගේම best practices සහ security tips ගැනත් කතා කලා. මේ knowledge එකෙන් ඔයාලට පුළුවන් වෙයි වඩාත් efficient, reliable සහ secure Docker images හදන්න. ලංකාවේ අපි වගේ දක්ෂ developersලට මේ දැනුම ගොඩක් වටිනවා.
දැන් ඔයාලට පුළුවන් මේ concepts ඔයාලගේ project වලට apply කරලා බලන්න. පොඩි Node.js, Python, Go application එකක් Dockerize කරලා බලන්න. Multi-stage builds පාවිච්චි කරලා image size එක අඩු කරන්න උත්සාහ කරන්න. අනිවාර්යයෙන්ම results දැක්කම පුදුම වෙයි! මේ ගැන ඔයාලට තියෙන අත්දැකීම්, ප්රශ්න පහත comment section එකේ share කරන්න. අපි හැමෝම එකතු වෙලා ඉගෙන ගමු!
ජය වේවා!