# 資訊通識與伺服器
:::success
### 工商時間
打得很好的東西
伺服器傳承的啦:https://serverbook.ckefgisc.org/
:::
## 資訊通識的Part
如果我不知道中文是什麼的名詞我就會用英文寫(? 大家可以自行查詢!
### Unix/Linux
#### 歷史
在 1960 年代,那時候的電腦就像是巨大的機器,占滿了整個房間,而且每一台都非常專門化,就像一台只能執行特定任務的巨型複雜打字機。
![image](https://hackmd.io/_uploads/rkbHMNAuR.png)
##### Multics
Multics(Multiplexed Information and Computing Service)是由麻省理工學院(MIT)、貝爾實驗室(Bell Labs)和通用電氣公司(GE)共同開發的一個大型操作系統項目,旨在創建一個多用戶、多任務的系統。
但這個計畫最終失敗於它太過複雜以及過於昂貴,以致於有了後面計畫的誕生。
##### Unix
在貝爾實驗室,Ken Thompson 和 Dennis Ritchie 等研究人員決定從頭開始,開發一個更簡單、更有效的系統。他們的目標是建造一個小巧靈活的系統,就像是一座精緻的小樓房,雖然不那麼華麗,但功能實用且易於維護。
這就是 Unix 的誕生。Unix 系統設計簡單、結構清晰,並且允許多個用戶同時使用,這使得它迅速在學術界和企業界流行起來。
##### Linux
到了 1990 年代,個人電腦(PC)變得越來越普及,人們需要一種可以在這些新型電腦上運行的高效操作系統。這時候,一位芬蘭的大學生 Linus Torvalds 出現了。Linus Torvalds 在 1991 年開始開發一個基於 Unix 原理的操作系統內核(Kernel),他稱之為 Linux。可以將 Linux 比作是一個開源(Open source)的建築藍圖,任何人都可以使用、修改它。
他在互聯網上分享了這個Kernel的代碼,並邀請其他人參與開發。這就像是在全球範圍內邀請建築師和工程師一起來改進這個建築藍圖。由於這種開源的模式,Linux 迅速得到了全球開發者的支持和貢獻,成為一個強大且靈活的操作系統。
![image](https://hackmd.io/_uploads/SyIRl40_R.png)
這個企鵝是 Linux 的吉祥物,他叫做 Tux 。
#### Basic Commands
這裡都是基礎的 Commands ,希望大家可以熟練。順帶一提,像 `ls -al` 的 `-al` 被稱為 Command flags ,用來改變 Command 執行的細節,有時候也會被叫做 Options 。
其中最重要的指令:`man` - 查看命令手冊
```bash
man 命令名
```
然後它就會詳細跟你講那個命令怎麼用,~~比我下面寫的詳細。~~
另外也可以看 [Linux Command Library](https://linuxcommandlibrary.com/) ,裡面有很多各式各樣的 Commands 可以參考。下面是 Linux 自帶的最基礎的 Commands :
1. `ls` - 列出目錄內容
```bash
ls
```
Flags:
- `-l`: 以詳細列表格式顯示文件和目錄,包括權限、所有者、大小和修改時間。
- `-a`: 顯示所有文件,包括隱藏文件(以 . 開頭的文件)。
2. `cd` - 切換目錄
```bash
cd
```
3. `pwd` - 打印工作目錄
```bash
pwd
```
4. `cp` - 複製文件或目錄
```bash
cp 源文件 目標文件
```
Flags:
- `-r`: 遞迴地(Recursively)複製整個源目錄到目標目錄。
5. `mv` - 移動或重命名文件或目錄
```bash
mv 源文件 目標文件
```
Flags:
- `-r`: 遞迴地(Recursively)移動整個源目錄到目標目錄。
6. `rm` - 刪除文件或目錄
```bash
rm 文件名
```
Flags:
- `-r`: 遞迴地(Recursively)刪除整個目錄。
- `-f`: 強制刪除。
7. `mkdir` - 創建目錄
```bash
mkdir 目錄名
```
8. `cat` - 顯示文件內容
```bash
cat 文件名
```
Flags:
- `-r`: 遞迴地(Recursively)建立路徑上的所有目錄。
後面是稍微難一點的,但等等可能會用到:
9. `ln` - 創建連結
```bash
ln 源文件 目標文件
```
連結有分成兩種,硬連結(Hard link)跟軟連結(Soft link),使得兩個檔案的內容同步:
- 硬連結:預設(不加flag)創建的是硬連結。每個連結檔案以及原本的檔案是等價的,也就是說,刪掉任何一個檔案並不會影響另一個檔案的存在。他們都共同指向同樣的硬碟位置,也因此不能夠實現跨硬碟的連結。
- 軟連結:又稱為符號連結(Symbolic Link),要創建一個軟連結需要加一個 flag: `-s` ,向下面這樣:
```bash
ln -s 源文件 目標文件
```
軟連結簡單來說就是捷徑,形成一個指標指向源文件,但一旦刪掉源文件,那所有指向它的軟連結都會失效。軟連結也能允許跨硬碟的傳輸,是比較靈活的連結。
10. `ssh` - 連線到遠端主機
```bash
ssh 用戶名@遠程主機
```
`ssh` 是 Secure shell 的縮寫,提供了一個安全的方式連線到遠端的主機。有些時候,為了區別不同的服務(可以看後面協定的章節),我們需要在連線的時候用 `-p` 來指定連接埠(Port):
```bash
ssh -p 連接埠 用戶名@遠程主機
```
11. `ping` - 測試遠端是否連通
```bash
ping 網址或IP位址
# example
ping www.google.com
```
12. `grep` - 一個搜尋工具
```
# 如果你要在你的輸入中搜尋的話
grep 要搜尋的正則表達式
# 如果你要在檔案中搜尋的話
grep 要搜尋的正則表達式 文件名
```
正則表達式(regex)由一組特殊的字符和符號組成,用來描述搜索模式。這些模式可以非常簡單,也可以非常複雜,取決於你的需求。
這個不是今天的重點,所以不會教你們怎麼寫正則表達式。如果真的需要的話可以考慮問ChatGPT,他還蠻擅長這個工作的,或者可以用 [RegexOne](https://regexone.com/) 這個網站來學。
13. 標準輸入輸出重定向(Redirection) 和 Pipe
- 輸出重定向:
輸出分為標準輸出(stdout)跟標準錯誤(stderr),如果要重定向 stdout :
```bash
命令 > 文件
# example
echo "Hello world!" > example.txt
```
他會把命令的stdout覆蓋並寫到指定文件,如果想要單純加在文件後面的話:
```bash
命令 >> 文件
# example
echo "Hello world!" >> example.txt
```
要重定向 stderr 的話:
```bash
命令 2> 文件
# example
ls DNE 2> error.txt
# 如果要加在文件後面
命令 2>> 文件
```
也可以一次定向兩個:
```bash
命令 &> 文件
# and also
命令 &>> 文件
```
- 輸入重定向:
輸入只有一種,也就是標準輸入(stdin),也是一樣的用法:
```bash
命令 < 文件
# example
python3 answer.py < input.txt
```
- Pipe(我覺得英文比較有人聽得懂)
Pipe 的用途把一個命令的輸出當作另一個命令的輸入,避免要先寫進一個檔案的麻煩:
```bash
# 把命令一的輸出當作命令二的輸入
命令一 | 命令二
# example
cat file.txt | grep "Hello world"
```
使用重定向和 Pipe 可以很大程度的提升工作效率。讓人能夠靈活地控制命令的輸入和輸出,並將多個命令組合起來,形成複雜的處理流水線。
### 常用套件(Packages)
我們先介紹一個 Command :
`sudo` - Superuser do
```bash
sudo 命令
```
用 `sudo` 執行命令的話,那我們便可以暫時取得最高級用戶 `root` 的權限,執行一些大程度改變系統的命令。(`sudo` 通常是個內建命令,如果不是的話記得要裝。)
先講如何安裝一個軟體或者套件,我們現在使用的是 Ubuntu 系統,是一個 Debian 架構的系統,而所有 Debian 架構的系統都可以使用 `apt` 或 `apt-get` 作為套件管理工具:
- 安裝
```bash
sudo apt install 套件
```
- 解除安裝
```bash
sudo apt remove 套件
```
- 更新 Packages
```bash
sudo apt update
```
#### 文字編輯器
在沒有圖形化介面的 Linux 的文字編輯器主要有 vim 、 nano 。
這裡是強烈推薦 vim :
![image](https://hackmd.io/_uploads/BkJfLHROA.png)
最重要的幾個鍵有:
- `i` - 進入 insert mode
- `Esc` - 回到 normal mode
- `:wq` - 儲存並退出
剩下的可以看大陸的[菜鳥教程](https://www.runoob.com/linux/linux-vim.html)
#### git - 版本管理工具
首先大家都應該要有一個 [GitHub](https://github.com/) 帳號(也不是不能用 [GitLab](https://about.gitlab.com/) ,但可能不是今天)。
`git` 其實是一門大學問,這裡就大概講一下:
- Clone - 複製一份程式碼
```bash
git clone <repo>
```
- Pull - 抓更新的程式碼下來
```bash
git pull
```
- Add - 新增要 Track 的檔案
```bash
# 特定檔案
git add <file_name>
# 目錄下全部
git add .
```
- Commit - 提交版本
```bash
git commit -m <commit_message>
```
- Push - 把新版本更新到repo
```bash
git push
```
然後有時間的話可以用一下 SSH key ,這是 [GitHub 的教學](https://docs.github.com/en/authentication/connecting-to-github-with-ssh)
#### systemd - 系統和服務管理
`systemd` 是 system daemon 的縮寫,其中 daemon 是常駐程式的意思。而 `systemd` 就是用來管理系統常駐程式的框架:
首先, `systemctl` 可以用來啟動或中止服務:
- 啟動服務
``` bash
sudo systemctl start <服務名>
```
- 中止服務
```bash
sudo systemctl stop <服務名>
```
- 重啟服務
```bash
sudo systemctl restart <服務名>
```
- 重新加載配置文件
```bash
sudo systemctl reload <服務名>
```
- 檢查服務狀態
```bash
sudo systemctl status <服務名>
```
~~現在不會也沒關係,反正等等會一直用到。~~
- 啟用服務(每次開機會自動開)
```bash
sudo systemctl enable <服務名>
```
- 禁用服務(啟用的相反)
```bash
sudo systemctl disable <服務名>
```
每個服務運行的內容被寫在一個單元文件(Unit file)裡,這個蠻複雜的,詳細的說明可以看 [Arch Wiki](https://man.archlinux.org/man/systemd.unit.5) (有點小硬)。
### 協定/協議(Protocols)
我們可以類比現實一下:
> 想像你在一個大型郵局裡,負責處理來自世界各地的信件和包裹。每個包裹都有自己的標籤,上面寫著發件人、收件人地址、郵政編碼等信息。這些標籤就像網絡協議中的規則,確保每個數據包都能準確無誤地送達目的地。
網絡協議是網絡通信的規則和約定,規範了數據如何在網絡上傳輸、接收和解碼。網路協議可以被分成 4 層 (或 5 層,以下 4 層加上 Physical Layer),每一層都依賴於下面一層的服務:
1. 應用層(Application Layer)
> 應用層就像是郵政系統的前台服務,提供了各種專門的服務窗口,如信件投遞、包裹郵寄、匯款等。
應用層會跟用戶互動並根據應用程式不同的需求,把資料給傳輸下去:
- HTTP/HTTPS - 用於網頁瀏覽
1. 客戶端請求:客戶端(如瀏覽器)發送一個 HTTP 請求到服務器。這個請求包含了方法(GET、POST 等)、URL 和 header。
2. 服務器響應:服務器接收到請求,處理後返回一個 HTTP response 。這個 response 包含了 status code 、 header 和數據(如 HTML 文件)。
HTTP 跟 HTTPS 都會有一個 header ,用來定義該操作的一些參數。
HTTPS (Port:443) 是安全版的 HTTP (Port:80) ,透SSL/TLS(Secure Sockets Layer/Transport Layer Security)來加密數據傳輸。
- DNS - 域名系統
它的主要作用是將人類易於記憶的域名(Domain Name)轉換成電腦能夠了解的 IP 位址。一旦你使用域名而非 IP 位址,電腦便會發送一個 DNS 請求,由本地的DNS解析器找尋伺服器上有沒有對應的域名,並返回 IP 位址。
2. 傳輸層(Transport Layer)
> 傳輸層就像是郵政系統中的包裹處理中心,負責將包裹按照正確的順序和完整性送達目的地,並處理包裹的跟蹤和確認。
傳輸層提供了端到端的通信服務,確保數據在應用層之間可靠地傳輸:
- TCP/UDP
TCP 是一種可靠的傳輸方法、會固定傳輸的順序,依靠多次握手來確保資料傳輸順利,但速度比較慢;而 UDP 是一種不可靠的傳輸方法,可能會造成部分資料的丟失,但速度比較快。
3. 網路層(Internet Layer)
> 網路層就像是郵政系統的分類中心,負責根據郵政編碼將信件和包裹路由到最終目的地。
網路層負責數據包的尋址和路由,確保數據包從源地址傳輸到目標地址:
- IP
IPv4:使用 32 位地址(如 192.168.1.1)。
IPv6:使用 128 位地址(如 2001:0db8:85a3:0000:0000:8a2e:0370:7334)。
4. 連結層(Link Layer)
> 鏈路層就像是郵遞員,負責將包裹從一個郵局送到另一個郵局,直到到達最終目的地。
鏈路層負責物理鏈路上的數據傳輸:
- Ethernet
- Wi-Fi
---
## 伺服器的Part
### 網頁伺服器軟體
web server 包含了一連串控制網路用戶如何訪問託管檔案 。HTTP 伺服器是其中一個部份,它理解 URLs 與 HTTP(瀏覽器用來觀察網頁的協議)。它能透過域名(domain name)訪問託管的網站,並將其內容遞送到終端用戶的設備上。
除此之外,web server 用途還包含反向代理、Http Cache、負載平衡器等等
### Apache vs Nginx
1. Apache HTTP Server
- 又稱為 httpd
- 由 Tim Berners Lee 開發並於 1995 年發布
- 由 Apache 基金會維護。
- 為全球約 46% 的網站提供支持
2. Nginx
- 由 Igor Sysoev 於 2004 年發布
- 逐漸取代 Apache
### Nginx 的基本使用
1. 指令
```bash=
# 安裝
sudo apt install nginx
# 啟動
sudo systemctl start nginx
# 注:使用 systemctl 啟動的服務,會自動在開機後重啟
# 重啟
sudo systemctl restart nginx
# 停止
sudo systemctl stop nginx
# 檢查狀態
sudo systemctl status nginx
```
2. 除錯
Nginx 若無法正確啟用,絕大多數時間是 port 80 或是 port 443 被其他服務站用。若用 5. 之方法查明為此原因,可以透過以下指令檢查誰監聽哪個口。
```bash=
sudo lsof -i -P -n | grep LISTEN
```
除此之外,也可以透過配置文件內
3. 配置文件
- 目錄:`/etc/nginx` (以下用這目錄的相對路徑表示)
- 主文件:`nginx.conf`
:::spoiler 寫法
```nginx=
user www-data; ##設定 Nginx 使用 www-data 用戶執行。
worker_processes auto; ##自動調整工作進程的數量
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf; ##包含額外的模塊配置文件
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
```
- `http` 階段裡放置 web server 相關設定
:::
- Virtual Host 文件目錄:
- `./conf.d/` (recommended)
- `./sites-enable/` -> `./sites-avaliable/`
- Virtual Host 文件寫法
```nginx=
upstream api {
server localhost:5000; #定義了要將 request proxy 過去的應用
}
server {
listen 80; # 監聽 port 80 (http)
listen [::]:80;
server_name dian.cjtsai.com; # 負責處理針對 dian.cjtsai.com 的請求
# 若為 _ ,代表任意網址
root /var/www/html; # 靜態網站放在哪
index index.html index.htm index.nginx-debian.html; # 首頁名稱
# 反向代理設定
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 將針對特定網址的請求,反向代理到別的東西
location /api {
proxy_pass http://api/;
}
}
```
8. 其他 Nginx 指令
```nginx=
# 如果你沒有systemctl 可以使用nginx -s下達各種指令
nginx -s start/stop/reload
# 檢查conf檔案是否可用
nginx -t
# 自訂義conf檔案路徑
nginx -c [conf_file]
```
## Docker
### 簡介
- 什麼是 Docker
- 一個類似於虛擬機的東東
- 可以十分輕量化的建立一個服務
- 確保系統、環境到哪裡都一樣
- 設定好安裝指令,可以簡易的部署到任意地方
- 三個基本概念 [:link:參考資料](https://philipzheng.gitbook.io/docker_practice/basic_concept)
- 映像檔(Image)
- 容器(Container)
- 倉庫(Repository)
- 映像檔(Image)
- 就是一個唯讀的模板
- 例如:一個映像檔可以包含一個完整的 ubuntu 作業系統環境,裡面僅安裝了 Apache 或使用者需要的其它應用程式。
- 映像檔可以從倉庫抓取,或是利用 Dockerfile 建立
- 映像檔可以用來建立 Container
- 容器(Container)
* 容器是一個運作的實體
* 可以啟動、開始、停止、刪除
* 每個容器都是相互隔離的
* 可以把它看作一個小 VM ,跑著特定的 linux
* 倉庫(Repository)
* 倉庫是集中存放映像檔檔案的場所
* 最大的公開倉庫是 Docker Hub
### 建立基本 Docker
```bash=
# 拉取 image
docker image pull ubuntu
# 查看 image 清單
docker image list
# 產生一個 ubuntu 並且輸出 Hello world
sudo docker run ubuntu /bin/echo 'Hello world'
# 產生一個 ubuntu 並且進入 bash
sudo docker run --name test ubuntu "/bin/bash"
# 查看現有的 container
docker ps -a
```
- [更多教學](https://philipzheng.gitbook.io/docker_practice/container/run)
### Dockerfile
#### 1. 什麼是 Dockerfile? (by chatGPT)
Dockerfile 是一個純文字檔案,包含了一系列指令,這些指令描述了如何構建一個 Docker 映像檔。透過 Dockerfile,可以自動化創建 Docker 映像檔,確保開發、測試和生產環境的一致性。
#### 2. 基本語法
每個 Dockerfile 通常會包含以下幾個部分:
- **FROM**: 指定基礎映像檔
- **RUN**: 執行命令
- **COPY** / **ADD**: 複製檔案到映像檔內
- **CMD** / **ENTRYPOINT**: 指定容器啟動時執行的命令
- **EXPOSE**: 暴露端口
- **ENV**: 設置環境變數
- **WORKDIR**: 設置工作目錄
#### 3. Dockerfile 範例 ------ 建立一個簡單的 Node.js 應用
1. 建立一個 Node.js 應用:
:::spoiler
```javascript
// app.js
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 World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
```
:::
2. 創建一個 `package.json` 檔案:
:::spoiler
```json
{
"name": "docker-node",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "Your Name",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.17.1"
}
}
```
:::
3. 創建 Dockerfile:
```dockerfile
# 使用官方的 Node.js 基礎映像檔
FROM node:14
# 設置工作目錄
WORKDIR /usr/src/app
# 複製 package.json 和 package-lock.json
COPY package*.json ./
# 安裝應用依賴
RUN npm install
# 複製應用程式源碼
COPY . .
# 暴露應用程式的端口
EXPOSE 3000
# 啟動應用程式
CMD ["node", "app.js"]
```
4. 建立和運行 Docker 映像檔:
```sh
# 建立映像檔
docker build -t my-node-app .
# 運行容器
docker run -p 3000:3000 my-node-app
```
### Docker-compose
* 可是,有些時候,但一個 Container 沒辦法完成所有事情
* Docker-compose: 一個指令,自動根據規則,完成 build image、啟動多個 container,並且操控多個 container
* docker-compose.yml 就是 container 的管理文件,只是採用 code 形式描述
#### Docker Compose 基本概念
* 服務 (Service): 一個應用的容器,定義在 docker-compose.yml 文件中。
* 網絡 (Network): 服務之間的通信方式,默認會為每個 Compose 應用創建一個網絡。
* 卷 (Volume): 持久化數據存儲,服務可以共享和持久化數據。
*
#### docker-compose.yml
以下是 docker-compose.yml 的基本範例,定義了一個簡單的 Web 應用,包含一個 Web 服務和一個 Redis 服務:
```yaml=
version: '3'
services:
web:
image: my-web-app:latest
ports:
- "5000:5000"
depends_on:
- redis
redis:
image: redis:alpine
```
#### docker-compose 指令
```bash=
# 啟動服務
docker-compose up
# 在背景執行
docker-compose up -d
# 停止服務
docker-compose down
```
#### 高級用法 (by chatgpt)
:::spoiler
##### 多服務定義
可以在 `docker-compose.yml` 文件中定義多個服務,例如 Web 應用和數據庫:
```yaml
version: '3'
services:
web:
image: my-web-app:latest
ports:
- "5000:5000"
depends_on:
- db
db:
image: postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
```
##### 使用卷來持久化數據
卷可以用來持久化數據,例如數據庫的數據:
```yaml
version: '3'
services:
db:
image: postgres:latest
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
```
##### 自定義網絡
可以定義自定義網絡來控制服務之間的通信:
```yaml
version: '3'
services:
web:
image: my-web-app:latest
networks:
- my-network
db:
image: postgres:latest
networks:
- my-network
networks:
my-network:
```
:::