今天我們以開發者的角度,實際走過 GitOps 的工作流程,這次 Lab 準備了 NodeJS 留言板應用。
進入 Cloud Shell 網站
建立所需檔案
cd ~/project
mkdir models views
touch models/message.js views/index.js
npm install express path mongoose method-override dotenv ejs
左上 Explorer -> Open Folder -> 選擇 project 資料夾 -> Open
const express = require('express')
const path = require('path');
const mongoose = require('mongoose');
const methodOverride = require('method-override');
const Message = require('./models/message');
const app = express();
const port = 8080
require('dotenv').config()
const DATABASEURL= `mongodb://${process.env.MONGO_INITDB_ROOT_USERNAME}:${process.env.MONGO_INITDB_ROOT_PASSWORD}@${process.env.MONGO_HOST}:27017/message?authSource=admin`;
mongoose.connect(DATABASEURL,{
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('CONNECTION SUCCESS!!'))
.catch(err => console.log(err));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true }));
app.use(methodOverride('_method'));
app.get('/', async (req, res) => {
const messages = await Message.find({});
res.render("index",{ messages });
})
app.post('/message', async (req, res) => {
const message = new Message(req.body.message);
await message.save();
res.redirect('/');
});
app.delete('/message/:id' , async (req,res) =>{
const { id } = req.params;
await Message.findByIdAndDelete(id);
res.redirect('/');
});
app.listen(port, () => {
console.log('Example app listening at port %s', port)
})
const mongoose = require("mongoose");
const messageSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
content: {
type: String,
required: true
}
});
const Message = mongoose.model("Message", messageSchema);
module.exports = Message;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IT-Home Project</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz"
crossorigin="anonymous">
</head>
<body style="background-color: #E8F0FE">
<nav class="navbar bg-dark navbar-dark">
<div class="container">
<a href="#" class="navbar-brand"><i class="fas fa-comment-dots"></i> Message Board</a>
</div>
</nav>
<section id="header" class="jumbotron text-center mt-4">
<h1 class="display-3"> Ithome Message Board</h1>
</section>
<div class="container mt-4">
<form action="/message" method="POST">
<div class="row justify-content-md-center">
<div class="col-2 offset-1">
<input type="text" name="message[name]" class="form-control" placeholder="user" value="Anonymous" required>
</div>
<div class="col-6">
<input type="text" name="message[content]" class="form-control" placeholder="message" required>
</div>
<div class="col-2">
<button class="btn btn-primary">Send</button>
</div>
</div>
</form>
</div>
<div class="container mt-5">
<table class="table table-striped">
<thead>
<tr>
<th scope="col" width="20%">Name</th>
<th scope="col" width="70%">Message</th>
<th scope="col" width="10%"></th>
</tr>
</thead>
<tbody id="teacherTable">
<% for(let message of messages) { %>
<tr>
<td><%= message.name %></td>
<td><%= message.content %></td>
<td>
<form class="d-inline" action="/message/<%= message.id %>?_method=DELETE" method="POST">
<button class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }%>
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
</body>
</html>
完整的程式碼可以到 WebApp 查看。
專案建立完成後,可以在 dev 環境建立 MongoDB 測試應用。
docker run -d -p 27017:27017 --name mongo \
-e MONGO_INITDB_ROOT_USERNAME=localuser \
-e MONGO_INITDB_ROOT_PASSWORD=localpasswd \
mongo
app.js
node app.js
網頁預覽->透過以下通訊預覽 : 8080
在 Cloud Shell 測試專案可以成功運行。
當專案完成準備進入部屬環境,開發者就可以上傳到 Git Repo ,並建立 Merge Request 來觸發 CI/CD Pipeline 。
git checkout dev
git add .
git commit -m "add message board"
git push origin dev
Merge Request
,等待測試 Pipeline 完成後按下 Merge
DevOps 的核心目標是讓開發完成到部屬的交付時間變得更迅速,透過 CI/CD Pipeline 將部屬工作自動化,開發者只需要將程式碼上傳,就能迅速完成部屬工作。