以下範例將使用 Ubuntu 18.04 建置 CoreDns 以及一台 Ubuntu 18.04 做測試。
CoreDns 簡單介紹:
CoreDns 是一個由 Golang 所開發的一套 Dns, 相當的靈活可以自行添加套件,而當 CoreDns 安裝完成後預設會先裝上 30個套件。
在要安裝 CoreDns 前因為他本身是由 golang 所開發的,所以環境需要先安裝 golang。
- 先安裝 git, 因為會從 github pull dns server repo 下來
sudo apt-get update -y
sudo apt-get install git -y
2. 安裝 make 指令
sudo apt-get -y install make
3. 安裝 go 套件
先下載 go.tar.gz 壓縮檔下來
wget https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
解壓縮 go.tar.gz
tar xvf go1.22.5.linux-amd64.tar.gz
將解壓縮出來的檔案移動至 /usr/local
sudo mv go /usr/local
在 ~/.bashrc 設定環境變數
export GOPATH=/home/ubuntu/go
export GOROOT=/usr/local/go
export GOBIN=$GOPATH/bin
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
設定完成後重新加載 ~/.bashrc
source ~/.bashrc
因為 GOPATH 設定的位置是 /home/ubuntu/go 所以要在 /home/ubuntu 建立 go 資料夾
cd ~ && mkdir go && mkdir ~/go/src ~/go/pkg ~/go/bin
參考資源:
4. 將 coredns pull 下來且進行編譯
git clone https://github.com/coredns/coredns
將 coredns 移到 GOPATH 下
sudo mv coredns ~/go
編譯 coredns
cd ~/go/coredns && make
參考資源:
設定 coredns 設定檔, coredns 設定檔的預設名稱為 Corefile。
編輯 Corefile
.:1053 {
whoami
log # log
}
執行 coredns 監聽的 port 改為 1053
./coredns -dns.port 1053
coredns 起來後再使用 dig 看能否查出 dns 資訊
dig @127.0.0.1 -p 1053
coredns 套件文件:
log Format 調整
log 的部分也可以自定義輸出格式, 修改 Corefile
將上方的 log 改為以下部分
log . "Protocol: {proto} Name: {name}, Remote: {remote}, Type: {type}, RequestSize: {size}, ResponseDuration: {duration}, ResponseCode: {rcode}, ResponseSize: {rsize}"
參數說明:
proto: 協定
name: domain name
remote: client ip
type: 請求種類, A Record 等
size: 請求的大小
duration: 回應的時間
rcode: 回應的代碼資訊
rsize: 回應的資料大小
設定完之後重新啟動並且執行 dig 即可以看到以下資訊
Reload Plugin
reload plugin 會每隔一段時間自動重新加載 Corefile。 我們在全域的 zone 增加 reload 設定
Corefile
. {
reload 10s
}
重新啟動 coredns, 會發現多輸出了 SHA512, reload 就是去檢查 SHA 是否有改變,有改變的話重新加載 Corefile
可以透過修改 log format 進行測試,觀察 Corefile 是否會重新加載。
Prometheus Plugin
可以將 CoreDns 的一些資訊 export 給 Prometheus。
在 Corefile 全域增加 prometheus 設定
Corefile
. {
prometheus
}
倘若有設定 reload 的話可以等待 reload 新的設定, 而 Prometheus 取得 CoreDns 資訊的路徑為 /metrics, 可以透過以下指令檢查是否可以取得 metric。
curl -X "GET" http://localhost:9153/metrics
Cache Plugin
設定 DNS 快取的時間, cache 的時間單位為秒。
在 Corefile 增加 cache 設定
. {
// 之前的設定
# 自行定義 cache 的時間長度
cache 10s
}
Etcd
可以將 DNS 的對應寫在 etcd 裡面。
注意! etcd 的對應是反過來的也就是,倘若網址為 test.helloworld, 那 push 到 etcd 的路徑要為 helloworld/test。
範例:
<Zone> {
etcd {
path /skydns # 可以自己設定
endpoint http://<public ip or private ip>:2379
fallthrough
}
}
以範例來講 test.helloworld 就會被設定在 etcd 的 /skydns/helloworld/test 路徑下。
設定 etcd 的指令如下
etcdctl put /skydns/helloworld/test '{"host":"<public ip>","ttl":60}'
Etcd 基本介紹可以參考這篇
DNS Server 設定
這邊因為此範例運行在 ec2 上,而 ec2 的 53 port 已被佔用了,所以使用以下指令進行關閉。
sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved
關閉完資後透過以下指令檢查是否已關閉
systemd-resolve --status
倘若沒有輸出資料代表已關閉。
且記得在 /etc/hosts 將 private ip 加入進去, 不然 sudo 會出現錯誤訊息。
127.0.0.1 ip-xxx-xx-x-xx
緊接著因為原先的 ec2 dns 被關閉了,所以在進行 apt-get 操作的時候域名解析失敗,所以要在 Corefile 增加 forward, 透過其他的 DNS Server 轉方出去。
Corefile
. {
forward . 8.8.8.8 1.1.1.1
reload 10s
prometheus
log
errors
}
然後 Corefile 可以再增加自己的 domain 資訊
{domain} {
file /home/ubuntu/go/coredns/config/{domain}
log
whoami
}
此處的 /home/ubuntu/go/coredns/config/{domain} 是設定 domain 的資訊
@ 3600 IN SOA {nameserver1} {nameserver2} (
2017042745 ; serial
7200 ; refresh (2 hours)
3600 ; retry (1 hour)
1209600 ; expire (2 weeks)
3600 ; minimum (1 hour)
)
3600 IN NS {nameserver1}
3600 IN NS {nameserver2}
{cname} IN A {public ip}
以上的 nameserver1, nameserver2 使用 Cloudflare nameserver , 因為我的 domain 是託管在 cloudflare 上。
參考資源:
Server 2 設定
安裝編輯 resolve conf 套件
sudo apt install resolvconf -y
進入 resolv.conf.d
cd /etc/resolvconf/resolv.conf.d
編輯 head 文件,增加自己建置的 nameserver
# dns server ec2 的 private ip
nameserver 172.xx.xx.xxx
編輯完成後重新加載設定
sudo resolvconf -u
也可透過以下指令檢查是否已經吃到所設定的 nameserver
systemd-resolve --status
參考文件:
CoreDns 背景執行
創建 systemd
cd /etc/systemd/system
sudo vim coredns.service
coredns.service 內容如下
[Unit]
Description=CoreDns Service
Documentation=https://coredns.io
After=network.target
[Service]
User=root
WorkingDirectory=/home/ubuntu/go/coredns
ExecStart=/bin/bash -c "/home/ubuntu/go/coredns/coredns --conf /home/ubuntu/go/coredns/Corefile >> /home/ubuntu/coredns.log"
ExecReload=/bin/kill -SIGUSR1 $MAINPID
NoNewPrivileges=yes
Restart=on-failure
[Install]
WantedBy=multi-user.target
重新加載 systemd
sudo systemctl daemon-reload
啟動 coredns.service
sudo systemctl start coredns
設定開機時啟動
sudo systemctl enable coredns
檢查 coredns 是否正在運行
sudo systemctl status coredns
Private Subnet 設定
這邊為了安全起見將 DNS Server 設定為 Private Subnet , 導致 public 的服務無法存取的 DNS Server, 因為這邊的概念做法是透過 DNS Server 去 mapping 內部網路的一些服務(不公開的)。
首先在 AWS Dashboard 創建一個新的 VPC
- 點選 VPC and more
設定 VPC 名稱以及 IPv4 CIDR block 並且 disable IPv6
2.VPC 設定 public subnet, private subnet, 這邊的 AZ, public sunbet, private subnet 可以依照自己的想法去設定數量。
private subnet 因為沒有對外的連線方式,因此要為他的 Route Table 設定 NAT Gateway, 使他可以連到外面,否則在進行 apt 指令操作的時候會連線失敗。
3.建置 NAT Gateway
4. 將 NAT Gateway 設定至 private subnet 所屬的 Route Table
5. 創建隸屬於 public subnet 的 ec2, 記得要 auto assign ip
6. 創建屬於 private subnet 的 ec2, 要確認是否需要 auto assign ip
以下為了方便將 public subnet ec2 的簡稱為 public ec2, 反之 private subnet 的 ec2 簡稱為 private ec2
7. 確認 public ec2 是否可以 ping 到 private ec2
8. 確認外網是否 ping 不到 private ec2
參考資源:
兩個不同的 VPC 如何互連
倘若 DNS Server 跟 第二台 Server 處於不同的 VPC 下的話,需要建立 Peer Connection。
- 選擇 Peer Connection
2. 點選創建 Peer Connection
3. 設定請求方以及接收方的 VPC, 都設定完成後點選 Accept
4. 在請求方以及接收方的 Route Table 設定對應的 CIRD 以及 Peer Connection,也就請求方 A 的 Route Table 要新增接收方 B 的 CIRD ,接收方 B 的 Route Table 也要新增請求方 A 的 CIRD 至 Route Table。
5. 確認請求方跟接收方的 Security Group 的 ICMP 是否都開啟,因為待會會透過 ping 去確認是否已經可以互連。
https://habil.dev/connection-between-two-different-vpc-with-aws-peering/
因為 DNS Server 位於 private subnet ,當想要 ssh 進入到機器內的話有兩種方式,一種是使用跳板機,另外一個則是使用 aws session manager。
跳板設定
~/.ssh/config 設定
Host <跳板機>
HostName <跳板機 public ip>
User <跳板機 username>
Port 22
IdentityFile ~/.ssh/<key pair>
IdentitiesOnly yes
Host <private ec2 主機>
HostName <Private ip>
User <username>
Port 22
IdentityFile ~/.ssh/<key pair>
IdentitiesOnly yes
ProxyJump <跳板機 Host, 也就是上方的 Host 名稱>
上面是透過跳板機連到 private ec2, 也可以透過 session manager 連線到 private subnet
Session Manager 連線
1.安裝 session manager
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
2. 解壓縮 session manager
unzip sessionmanager-bundle.zip
3. 安裝 session manager
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
4. 確認 session manager 是否安裝成功
./sessionmanager-bundle/install -h
5. 設定具有 ssm 連線的 role
點選 Create Role
Use Case 選擇 EC2
Permission 給予 AmazonSSMManagedInstanceCore, 後按下新增
6. 將 ssm role assign 給 ec2
7. 設定 ~/.ssh/config
Host <ec2 instance id>
User ubuntu
Port 22
IdentityFile <pem key>
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p '"
8. 測試是否可以連線成功
ssh <ec2 instance id>
參考資源: