时光匆匆,发现自己已经很久没有动笔写博客了。瞥了一眼掘金,上一篇博客居然还停留在22年。五年间,似乎自己变得越发慵懒,或许是因为一旦进入舒适区,就不太愿意再去挑战自己,不管是在技术上还是生活中。刚毕业时,心怀梦想,全力钻研各种新技术,渴望进入大厂一窥天地,然而渐渐发现,这一切似乎并没有给自己带来太多的惊喜。最近和一位同学聊天,他说自己坚持工作的动力就是知道下周就发工资了。或许对我来说也是如此,只有在即将面试时才会匆匆刷技术文档,编写开源代码。废话不多说,直入正题吧。
简单说一下写这篇博客的原因吧,一是最近闲着也是闲着,写与不写周末这样都过去了;二是用最近很火的庆余年2中话说就是做事要留痕,毕竟也是实打实的将云服务迁移到了自建服务器上嘛,写写日志。
物联网应用基建
云服务器,大家熟悉到不能在熟悉的词,不管什么岗位,只要是和计算机沾边的工作,什么阿里云、腾讯云、华为云
天翼云,国内外有一大批的云服务商。
不讨论企业级的应用,单说对于个人开发者和技术爱好者来说,云服务器给确实带来了许多便利和好处。云服务器的灵活性和方便性大大降低了技术学习的试错成本,通过云服务器可以随意的折腾系统,部署服务,有问题大不了直接重置服务器,也不用担心主板烧了,开不了机。
但是,就像所有事物一样,云服务器也有它的弊端。首先是价格问题,虽然云服务器提供了按需付费的方式,但长期使用可能会带来不小的花费,特别是对于个人开发者来说,这就是是个负担。此外,对于一些技术水平较低的人来说,如果要基于物理机自己搭建和管理服务器可能会有一定的技术难度,需要花费额外的时间和精力来学习和解决各种技术问题。因此,这篇博客的意义就在于给技术萌新指一条除云服务器之外的一条道 ,当然技术大佬们也可以一起指点指点。
起因
这几年断断续续的做了一些个人的项目,都部署在云服务器上,这些服务器大都是三年前捡漏购置的云服务器,比如三年前以极低价买了台某讯云4核8G的。最近这几台服务器都濒临到期,一看账单就是不想掏的冤枉钱,比如说这个,2核4g 续一年就是一千多。
再比如说这个更离谱一年七千多
因为大部分都是流量非常小的应用,还不如自己搞台物理机搭建,搞搞穿透,配置又高,成本又低,尔乐而不为,说干就干,所以说到底还是穷,不想掏这些资源的费用。
准备台物理主机
搭建服务器受首先就得有台主机,家里其实是有废弃的台式电脑,最开始想想也能用,但看了下能耗和噪音,确实是有些不太理想,服务器这东西总不能频繁的关机吧,耗电确实是个问题,而且分贝太高,风扇呼呼的转影响睡眠。所以目光最后投向了最近这两年特火的迷你主机,千元内的新机大部分配置相当可以,能耗、配置、造影都是相当能打的,之前论坛说零刻系列性价比可以,但看了看价格还是在预期之外,最后还是选了铭凡系列的UNI100,4核CPU + 500G存储 + 16G内存,配置杠杠的, 可以把之前的的伪K83集群直接改成单节点,物理机准备就绪接下来就是系统改造。
系统装配
Ubuntu Server安装
服务器端的操作系统很多,随便选一个适合自己的操作系统就行,我个人习惯 Ubuntu, Ubuntu有各种的发行版,常见的 Ubuntu Desktop、Ubuntu Server、Kubuntu等,直接上Ubuntu Server 中规中矩。Ubuntu Desktop 它是面向桌面、笔记本电脑和工作站的版本。该版本包括了大量的预装软件,当作服务器来说太重了。
IOS 下载
直接进入官网Ubuntu Server找到适合的版本下载,文件比较大,耐心等待下载完毕即可。
启动盘
大部分重装系统方式都是通过启动盘的方式。找一个口碑比较好的启动盘制作工具,此处以 UltraISO 为例, 插入空闲的U盘后直接写入IOS即可,按提示步骤即可。
系统安装
启动盘制作完成后,插入主机,通过 BIOS 启动进入系统安装界面,不同型号的电脑进入方式可能不一样,大部分 长按 F2 或者 F7 再或者 F8。
进入安装引导菜单
选择 【Try or Install Ubuntu Server 】 安装系统。
选择安装语言 && 不更新安装
默认选择 【 English 】,没有中文,可以不用找了,然后继续选择 【Continue without updating】
选择键盘布局
默认就好,不用修改
选择安装类型
默认Ubuntu Server, 不用改直接下一步;
Network配置(非常重要)
网络配置非常重要,不熟悉的建议第一次配置成DHCP(自动获取IP地址),系统装配完成后再设置静态IP,新手上路第一次建议直接配置wifi,配置wifi 时选中 对应的端口选中DHCP 即可进入wifi的连接界面(这里忘记截图了)。
代理配置默认不填
atp源 配置
这个看自己情况吧,也可以配置成国内的,像阿里的,清华的都可以
分区配置
新手不建议改,默认就好,老手其实也可以不改(没有截图,网上找了张顶一顶);
配置登录的普通用户和主机名
安装ssh
重启
安装完成后重启
服务器组网
系统安装完成后,建议将机器的IP固定,一是 连接SSH 方便,二是代码开发时服务时不用每次调整Api。
先通过 ip addr
查看当前主机的ip 地址(安装系统时配置了 DHCP, 已经获取了一个可用的 ip ),如果没有特殊要求,可以直接拿这个 IP 当作静态IP, 按正常的架构来说,服务器应该有独立的路由,单本次因为只有单节点,故家中的路由器直接拿来用。
网络配置
Ubuntu 的网络配置文件一般在 /etc/netplan 目录下,至于哪个文件,不同的版本不太一样,例如50-cloud-init.yaml,找到配置文件后直接编辑配置
yaml
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
enp1s0:
dhcp4: false # 宽带的接口也禁用掉自动获取IP
enp3s0:
dhcp4: false # 宽带的接口也禁用掉自动获取IP
version: 2
wifis:
wlo1:
access-points:
"wifi 名称": # wifi 名称,无法直接输入中文的,需要先进行ascii 编码
password: 'wifi密码' # wifi的密码
dhcp4: false # 禁用掉自动获取IP
routes: # 路由配置
- to: 0.0.0.0/0 # 所有的来源
via: x.x.x.x # 全部路由到网关层面
addresses: [192.168.3.26/24] # 需要固定的IP
nameservers:
addresses: ## DNS 配置 国内建议配置国内的解析
- 180.76.76.76
- 114.114.114.114
- 8.8.8.8
编辑设置完成后执行更新即可
sudo netplan apply
sudo systemctl restart systemd-networkd
国内常用的DNS
- 114DNS服务 114.114.114.114
- 阿里DNS服务 223.5.5.5
- 百度DNS服务 180.76.76.76
- 腾讯DNS(DNSPod ) 119.29.29.29
常见问题
1. 有部分的 Ip、域名无法 ping 通
设置wifi 后 可以ping 通 www.baidu.com 但无法ping 通外部的 ip 例如 ping 114.114.114.114 显示ping: connect: Network is unreachable
这是目前的 route , 发现当前并未配置网关。
sql
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.3.0 0.0.0.0 255.255.255.0 U 0 0 0 wlo1
针对这种问题,只需要编辑 配置网关路由即可 sudo vi /etc/netplan/50-cloud-init.yaml
yaml
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
enp1s0:
dhcp4: false # 宽带的接口也禁用掉自动获取IP
enp3s0:
dhcp4: false # 宽带的接口也禁用掉自动获取IP
version: 2
wifis:
wlo1:
access-points:
"wifi 名称": # wifi 名称,无法直接输入中文的,需要先进行ascii 编码
password: 'wifi密码' # wifi的密码
dhcp4: false # 禁用掉自动获取IP
routes: # 路由配置
- to: 0.0.0.0/0 # 所有的来源
via: x.x.x.x # 全部路由到网关层面
addresses: [192.168.3.26/24] # 需要固定的IP
nameservers:
addresses: ## DNS 配置 国内建议配置国内的解析
- 180.76.76.76
- 114.114.114.114
- 8.8.8.8
发现配置后还是无法ping 通 发现是114.114.114.144 的dns 解析有问题时可以替换别的 DNS,例如百度的dns (180.76.76.76)。此时大概率就可以了,不论是内网还是公网。
python
marvin@ubuntu:~$ ping www.baidu.com
PING www.baidu.com (36.155.132.76) 56(84) bytes of data.
64 bytes from 36.155.132.76: icmp_seq=1 ttl=52 time=13.7 ms
64 bytes from 36.155.132.76: icmp_seq=2 ttl=52 time=15.4 ms
64 bytes from 36.155.132.76: icmp_seq=3 ttl=52 time=15.0 ms
^C
--- www.baidu.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 13.687/14.681/15.373/0.720 ms
python
marvin@ubuntu:~$ ping 180.76.76.76
PING 180.76.76.76 (180.76.76.76) 56(84) bytes of data.
64 bytes from 180.76.76.76: icmp_seq=1 ttl=50 time=38.9 ms
64 bytes from 180.76.76.76: icmp_seq=2 ttl=50 time=40.7 ms
64 bytes from 180.76.76.76: icmp_seq=3 ttl=50 time=40.6 ms
^C
--- 180.76.76.76 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 38.917/40.068/40.675/0.814 ms
python
marvin@ubuntu:~$ ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.114 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.116 ms
^C
--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2063ms
rtt min/avg/max/mdev = 0.089/0.106/0.116/0.012 ms
至此基于服务器的基础已经安装完毕,接下来就是安装一些底层的基座,例如 docker 、k8s 集群等。
基础设施
docker
Docker 提供了一键脚本,可以直接使用进行安装,安装命令如下所示:
vbnet
curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
安装完成以后通过可以 docker version 即可确认到版本信息:
yaml
root@canyuegongzi:~# docker version
Client: Docker Engine - Community
Version: 20.10.6
API version: 1.41
Go version: go1.13.15
Git commit: 370c289
Built: Fri Apr 9 22:46:01 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.6
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: 8728dd2
Built: Fri Apr 9 22:44:13 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.4
GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc:
Version: 1.0.0-rc93
GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
docker-init:
Version: 0.19.0
GitCommit: de40ad0
通过 systemctl start docker 启动 Docker:
arduino
systemctl start docker // 启动 docker
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
k3s
k3s 是简化版的K8S,麻雀虽小,五脏俱全,特别喜欢轻量级的集群部署,详细信息可以移步 K3S
k3s 早期时候因为国内网络的原因,无法通过官方的提供的脚本一键安装,只能通过离线安装的方式。2020 年之后官方提供了国内环境下的安装脚本。
bash
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -s - --docker
通过 k3s kubectl get node 验证 k3s 是否安装成功。
arduino
k3s kubectl get node
arduino
k3s kubectl get node
NAME STATUS ROLES AGE VERSION
ubuntu Ready control-plane,master 87s v1.20.6+k3s1
至此一些底层的软件部署完毕,开始部署一些上层的应用,诸如 Mysql, redis 等
mysql
此处只是简单贴了下 mysql 的部署 yml 配置,其中的具体配置信息,感兴趣的可以深度钻研下 k8S 的配置。
yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-data-dev.cnf
namespace: test
data:
my.cnf: |
[mysqld]
port = 3306
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
skip-character-set-client-handshake=1
default-storage-engine=INNODB
max_allowed_packet = 500M
explicit_defaults_for_timestamp=1
long_query_time = 10
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-1gi-mysql-data
labels:
type: local
spec:
storageClassName: manual-mysql-data
capacity:
storage: 4Gi
accessModes:
- ReadWriteOnce # 卷可以被一个节点以读写方式挂载
hostPath:
path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data-pvc
namespace: gpt
spec:
storageClassName: manual-mysql-data
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 4Gi
---
# https://www.cnblogs.com/JoePotter/p/16703055.html
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-data-deployment
namespace: gpt
labels:
app: mysql-data
spec:
replicas: 1
selector:
matchLabels:
app: mysql-data
template:
metadata:
labels:
app: mysql-data
spec:
containers:
- name: mysql-data
#image: mysql:8.0.24 # mysql:8.0.30-debian
image: mysql:8.0.24
env:
- name: MYSQL_ROOT_PASSWORD
value: 123456
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql-data
- name: mysql-config
mountPath: /etc/mysql/mysql.conf.d
imagePullSecrets:
- name: aliyun-register-pwd
volumes:
- name: mysql-data
hostPath:
path: /data/mysql
type: Directory
- name: mysql-config
hostPath:
path: /data/mysql-config
type: Directory
## --tls-san 参数是可以允许公网 ip 证书
---
apiVersion: v1
kind: Service
metadata:
name: mysql-data-service
namespace: gpt
spec:
type: LoadBalancer
selector:
app: mysql-data
ports:
- protocol: TCP
port: 3306
targetPort: 3306
nodePort: 3306
redis
redis 也类似,K8S 的内容不在本次博客之内,感兴趣的可以深度学习 K8S 的运维之道。
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis
namespace: test
data:
redis.conf: |+
requirepass 123456
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events Ex
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-1gi
labels:
type: local
spec:
storageClassName: manual-redis
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce # 卷可以被一个节点以读写方式挂载
hostPath:
path: "/mnt/data"
# deploy nacos pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
namespace: gpt
spec:
storageClassName: manual-redis
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: gpt
labels:
app: redis
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
#image: redis
image: registry.cn-hangzhou.aliyuncs.com/redis:2.1.1
imagePullPolicy: Always
command: ["redis-server","/etc/redis/redis.conf"]
ports:
- containerPort: 6379
volumeMounts:
- name: redis-config
mountPath: /etc/redis/redis.conf
subPath: redis.conf
- name: redis-persistent-storage
mountPath: /data
imagePullSecrets:
- name: aliyun-register-pwd
volumes:
- name: redis-config
configMap:
name: redis
items:
- key: redis.conf
path: redis.conf
- name: redis-persistent-storage
persistentVolumeClaim:
claimName: redis-pvc
---
kind: Service
apiVersion: v1
metadata:
name: redis
namespace: gpt
spec:
type: LoadBalancer
selector:
app: redis
ports:
- port: 6379
protocol: TCP
targetPort: 6379
业务应用
业务应用 此处也不再录累赘,后续有时间可以挑几个应用做示例。
网络穿透
暂时还没有做这部分的能力,下周完成后再做博客分享。