Skip to main content

10 posts tagged with "ProblemSolved"

View All Tags

· One min read
CheverJohn

这次的排错过程,主要是由我的 mentor 主导的,这边也给出了我导师的 github 账号,有兴趣的可以去交流一下哦。

tail -f logs/error.log

首先 static/img/2022-02-08-记录一次排错/image-20220208223242984.png image-20220208231005934

image-20220208230949696

image-20220208230815850

image-20220208230709047

  1. 得到 etcd 中所有的路由信息
etcdctl get / --prefix --keys-only
  1. tail 日志信息
tail -f logs/error.log
  1. 删除 etcd 中所有的 APISIX 路由数据
etcdctl del /apisix/routes --prefix
  1. 这边也记录一下 etcd 的官方关闭命令,其实也可以参考其他进程类关闭的方法:
kill `pgrep etcd`

来自于 etcd 官方链接

· 3 min read
CheverJohn

我的问题描述

  1. 无法跑测试(APISIX 的);
  2. Nginx 会启动多个进程。

然后我复现的命令如下可见

export PERL5LIB=.:$PERL5LIB:/home/api7/dev_cj/apisix

export PATH=/usr/local/openresty/nginx/sbin:$PATH

prove ....../example.t

然后就出现一个问题端口占用

解决办法:当跑测试的时候,因为 APISIX 会启动upstream 端口,所以如果不关闭 openresty 的阿虎,就会遇到端口占用的问题。

然后我运行

netstat -nultp

复现了 多个 nginx 进程的问题,

运行

ps -ef | grep nginx

发现了多个进程,意识到我的 openresty 还开着。

关闭 openresty

openresty -s stop

然后利用kill -9 杀掉了很多个进程。这边我采取了笨方法,一个进程一个进程杀掉了,可以不用 -9 ,这边 remark 一下。

kill -9 76007
kill -9 76008
kill -9 76009

APISIX 重启了一切正常

总结

ps -ef | grep nginx

这个命令还是要记记牢。

2022年 3月 8日

细节问题:没想到已经跑通测试的我,还是在新的开发机上跑测试框架遇到了问题。本次主要问题在于 一个安装包问题,所以说环境是真的无语,还是得设置到代理啊。我设置了git 的代理解决了问题, 详情方法,请参考 link ,我的主要疏忽在于,没注意端口, 因为之前实在 Windows 本上做开发的,用的是 v2ray,端口是 10808,没曾想就照着走错了,离谱啊。此处 mark 一下,需要注意。

然后还有一个点需要注意一下,make depsLUAROCKS_SERVER=https://luarocks.cn make deps 可以混着用,over。

放上遇到问题的图:

我又遇到问题啦呜呜呜

放上解决问题之后的图片:

解决问题就是爽啊!

· 2 min read
CheverJohn

本篇文章主要针对 APISIX 的插件开发,以及核心开发,配置相应的测试框架,并跑通。

首先我通过 git clone 将 APISIX 源码仓库 clone 到本地。

然后搭配另外安装的 etcd 和 OpenResty,将一些例子请求跑起来。

然后就开始我们主要的配置测试框架过程。这边对于 APISIX、OpenResty、NGINX 皆可用。

首先如果想要获取对测试框架的基本知识,请浏览此链接,这对接下来的很多操作都很有帮助。

然后还有一些基本的经验可以学习。

先配置

首先将 APISIX 加入到框架中去

export PERL5LIB=.:$PERL5LIB:/home/api7/dev_cj/apisix

然后配置OpenResty 中的 NGINX 的环境变量配置

export PATH=/usr/local/openresty/nginx/sbin:$PATH

小知识

--- ONLY

在测试案例中加入 --- ONLY or --- SKIP 可以仅测试一个案例,可以大大加快速度。

ONLY只做一个测试例子

--- SKIP

跳过这一个测试案例,其他都跑

小知识

这边有一个专属于 APISIX 的小知识,跑测试前要下载子模块(submoudle)。

git submodule update --init --recursive

如果你跑测试的时候遇到这样的报错: 缺依赖

只需要运行上面的命令即可

· One min read
CheverJohn

以 VMware 为示范

首先配置桥接网络,然后配置静态网络

然后进行以下命令

export https_proxy=https://192.168.1.102:10809

export http_proxy=http://192.168.1.102:10809

对于 git ,配置命令如下

git config --global http.proxy http://192.168.1.102:10809

git config --global https.proxy https://192.168.1.102:10809

git config --global --unset http.proxy

git config --global --unset https.proxy

· 14 min read
CheverJohn

本篇博客,详细讲述一个 issues 的解决过程,享受解决问题的快乐吧:)

起源

当我浏览我关注的 Apache APISIX 社区的时候,发现了一个非常符合我的 issues。这是一个关于 GraphQL 的issues,正好我有关于 GraphQL 的了解,便想着接下这个 issues 以锻炼自己的能力叭。

接下来讲述发现的过程:

issue 详情

看到 issue (标题为 bug: ctx.lua#59 parse_graphql(ctx) #6266 ),我刚开始看 issues 的时候,还以为是这位老哥不会使用 APISIX ,居然在发送请求的时候漏掉 -X POST (没想到最后还是我格局小了)

首先看 issue 的描述

use whole request body to parse graphql will get parse error. graphql request body is json , example :{"query":"query{getUser{name age}}","variables":null},

{"query":
"query{
getUser{
name age
}
}",
"variables":null
}

not query{getUser{name age}}

query{
getUser{
name
age
}
}

我简单描述一下,这个问题就是说当他使用请求体为 json 的请求时,出现 parse error 的问题。

这边还是要抽自己一下,他都明确说了,没有用 query 的方式,我还在后边用我的 query 跟他解释,离谱,我该反省~

curl -X POST http://127.0.0.1:9080/graphql -d '
query getUser {
owner {
name
}
repo {
created
}
}'

他给出了自己的环境配置

Environment

  • apisix version (cmd: apisix version): apache/apisix:2.12.0-alpine
  • OS (cmd: uname -a): docker
  • OpenResty / Nginx version (cmd: nginx -V or openresty -V): null
  • etcd version, if have (cmd: run curl http://127.0.0.1:9090/v1/server_info to get the info from server-info API): bitnami/etcd:3.4.15
  • apisix-dashboard version, if have: apache/apisix-dashboard:2.10.1-alpine

然后他给出了自己的复现过程

Reproduce

  1. define graphql
query {
getUser:User
}

type User{
name:String
age:String
}
  1. add route
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"methods": ["POST"],
"uri": "/graphql",
"vars": [
["graphql_operation", "==", "query"],
["graphql_name", "==", "getUser"]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
  1. perform graphql request by curl
curl 'http://127.0.0.1:9080/graphql' \
-H 'Content-Type: text/plain;charset=UTF-8' \
-H 'Accept: */*' \
--data-raw '{"query":"query getUser{getUser{name age}}","variables":null}' \
--compressed

上方请求化简

curl 'http://127.0.0.1:9080/graphql' \
-H 'Content-Type: text/plain;charset=UTF-8' \
-H 'Accept: */*' \
--data-raw '
{"query":"query getUser {
getUser {
name
age
}
}",
"variables":null
}' \
--compressed

Actual result

HTTP/1.1 404 Not Found Date: Tue, 08 Feb 2022 07:39:16 GMT Content-Type: text/plain; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive

{ "error_msg": "404 Route Not Found" }

Error log

2022/02/08 07:39:16 [error] 45#45: *1085159 [lua] ctx.lua:80: get_parsed_graphql(): failed to parse graphql: Syntax error near line 1 body:

Expected result

success

issue 提出者认为

一个正常的 graphql 请求应该是这样的:

curl 'https://api.mocki.io/v2/c4d7a195/graphql' \
-H 'authority: api.mocki.io' \
-H 'accept: */*' \
-H 'content-type: application/json' \
-H 'origin: https://api.mocki.io' \
--data-raw '{"operationName":"getUser","variables":{},"query":"query getUser {\n user(id: \"4dc70521-22bb-4396-b37a-4a927c66d43b\") {\n id\n email\n name\n }\n}\n"}' \
--compressed

会返回

{
"data": {
"user": {
"id": "Hello World",
"email": "Hello World",
"name": "Hello World"
}
}
}

而且

A standard GraphQL POST request should use the application/json content type, and include a JSON-encoded body of the following form:

{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... }
}

see official graphql document, https://graphql.org/learn/serving-over-http/#post-request

and --data will perform request with POST method ,see curl document

A standard GraphQL POST request should use the application/json content type, and include a JSON-encoded body of the following form:

{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... }
}

see official graphql document, https://graphql.org/learn/serving-over-http/#post-request

and --data will perform request with POST method ,see curl document

对于 curl 工具的使用

$ curl --help
Usage: curl [options...] <url>
-d, --data <data> **HTTP POST data**
...

use -v to print verbose log

curl -v 'https://api.mocki.io/v2/c4d7a195/graphql' \
-H 'authority: api.mocki.io' \
-H 'accept: */*' \
-H 'content-type: application/json' \
-H 'origin: https://api.mocki.io' \
--data-raw '{"operationName":"getUser","variables":{},"query":"query getUser {\n user(id: \"4dc70521-22bb-4396-b37a-4a927c66d43b\") {\n id\n email\n name\n }\n}\n"}' \
--compressed

issue 提出者原话:

it will print something like this > POST /v2/c4d7a195/graphql HTTP/2, thought i'm not use -X POST

sorry, I'm try to discuss about how APISIX deal with graphql request. it seems that the mock GraphQL data of APISIX is not a standard GraphQL request.

得出结论: mock GraphQL data of APISIX is not a standard GraphQL request.

评估需求

看过这个 issue 之后,思考了 APISIX 中的 GraphQL 到底是什么。或许 APISIX 支持的是假的 GraphQL?思考明白之后才能动手做。

之前应该是只做了这个:If the "application/graphql" Content-Type header is present, treat the HTTP POST body contents as the GraphQL query string.

curl -v -H "Content-Type: application/graphql" -d "{ hello }"  "localhost:3000/graphql" 

需要指定 content-type 了

所以我对于这个 issue 的结论就是:需要 fix 三部分

  1. 解决 POST JSON的问题,让 APISIX 支持 JSON 格式的 POST;
  2. 支持 GET 。

其实根据这篇文档

一个标准的 GraphQL POST 请求就应该使用 application/json content type, 然后包括 json 格式的body在里边。

但对于目前的 GraphQL 在 APISIX 中的应用来讲,是可以通过 "application/graphql" Content-Type 的形式绕过的。参考文档中的这句:

If the "application/graphql" Content-Type header is present, treat the HTTP POST body contents as the GraphQL query string.

重点:点睛之笔

https://graphql.org/learn/serving-over-http/ 参考官方的文档,实际上 APISIX 现在处理的场景是

If the "application/graphql" Content-Type header is present, treat the HTTP POST body contents as the GraphQL query string.

APISIX 暂时只能够实现 GraphQL query 的功能。

我们需要 json 格式的功能 最好还要加上 “GET” 的功能。

可参考的 GraphQL 官方文档

https://graphql.org/learn/serving-over-http/#post-request

https://graphql.org/learn/serving-over-http/#post-request

评估工作情况

第一次评估

我认为我需要修改 graphql-lua 库中的 parse.lua

curl 'http://127.0.0.1:9080/graphql' \
-H 'Content-Type: text/plain;charset=UTF-8' \
-H 'Accept: */*' \
-d '{"query":"query getUser{getUser{name age}}","variables":null}' \
--compressed

源码分析

找到 GraphQL 在 APISIX 中的代码,主要有关系的只有apisix/core/ctx.lua 中有相关代码。其实 APISIX 依靠的

--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core_str = require("apisix.core.string")
local core_tab = require("apisix.core.table")
local request = require("apisix.core.request")
local log = require("apisix.core.log")
local config_local = require("apisix.core.config_local")
local tablepool = require("tablepool")
local get_var = require("resty.ngxvar").fetch
local get_request = require("resty.ngxvar").request
local ck = require "resty.cookie"
local gq_parse = require("graphql").parse
local setmetatable = setmetatable
local sub_str = string.sub
local ngx = ngx
local ngx_var = ngx.var
local re_gsub = ngx.re.gsub
local ipairs = ipairs
local type = type
local error = error
local pcall = pcall


local _M = {version = 0.2}
local GRAPHQL_DEFAULT_MAX_SIZE = 1048576 -- 1MiB


local function parse_graphql(ctx)
local local_conf, err = config_local.local_conf()
if not local_conf then
return nil, "failed to get local conf: " .. err
end

local max_size = GRAPHQL_DEFAULT_MAX_SIZE
local size = core_tab.try_read_attr(local_conf, "graphql", "max_size")
if size then
max_size = size
end

local body, err = request.get_body(max_size, ctx)
if not body then
return nil, "failed to read graphql body: " .. err
end

local ok, res = pcall(gq_parse, body)
if not ok then
return nil, "failed to parse graphql: " .. res .. " body: " .. body
end

if #res.definitions == 0 then
return nil, "empty graphql: " .. body
end

return res
end


local function get_parsed_graphql()
local ctx = ngx.ctx.api_ctx
if ctx._graphql then
return ctx._graphql
end

local res, err = parse_graphql(ctx)
if not res then
log.error(err)
ctx._graphql = {}
return ctx._graphql
end

if #res.definitions > 1 then
log.warn("Multiple operations are not supported.",
"Only the first one is handled")
end

local def = res.definitions[1]
local fields = def.selectionSet.selections
local root_fields = core_tab.new(#fields, 0)
for i, f in ipairs(fields) do
root_fields[i] = f.name.value
end

local name = ""
if def.name and def.name.value then
name = def.name.value
end

ctx._graphql = {
name = name,
operation = def.operation,
root_fields = root_fields,
}

return ctx._graphql
end


do
-- 获取特殊var的方法
local var_methods = {
method = ngx.req.get_method,
-- ref: https://github.com/cloudflare/lua-resty-cookie
cookie = function ()
if ngx.var.http_cookie then
return ck:new()
end
end
}

local no_cacheable_var_names = {
-- var.args should not be cached as it can be changed via set_uri_args
args = true,
is_args = true,
}

local ngx_var_names = {
upstream_scheme = true,
upstream_host = true,
upstream_upgrade = true,
upstream_connection = true,
upstream_uri = true,

upstream_mirror_host = true,

upstream_cache_zone = true,
upstream_cache_zone_info = true,
upstream_no_cache = true,
upstream_cache_key = true,
upstream_cache_bypass = true,

var_x_forwarded_proto = true,
}

local mt = {
-- 重载 hash 元方法
-- t 是 self
__index = function(t, key)

-- 若 cache table 存在直接返回
local cached = t._cache[key]
if cached ~= nil then
return cached
end

if type(key) ~= "string" then
error("invalid argument, expect string value", 2)
end

local val
-- 如果是特殊类型, 使用特定方法获取
local method = var_methods[key]
if method then
val = method()

elseif core_str.has_prefix(key, "cookie_") then
-- 通过 var_methods 访问到 resty.cookie
local cookie = t.cookie
if cookie then
local err
val, err = cookie:get(sub_str(key, 8))
if err then
log.warn("failed to fetch cookie value by key: ",
key, " error: ", err)
end
end

elseif core_str.has_prefix(key, "arg_") then
local arg_key = sub_str(key, 5)
local args = request.get_uri_args()[arg_key]
if args then
if type(args) == "table" then
val = args[1]
else
val = args
end
end

elseif core_str.has_prefix(key, "http_") then
key = key:lower()
key = re_gsub(key, "-", "_", "jo")
-- 最终通过 ngx.var 获取
val = get_var(key, t._request)

elseif core_str.has_prefix(key, "graphql_") then
-- trim the "graphql_" prefix
key = sub_str(key, 9)
val = get_parsed_graphql()[key]

elseif key == "route_id" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.route_id

elseif key == "service_id" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.service_id

elseif key == "consumer_name" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.consumer_name

elseif key == "route_name" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.route_name

elseif key == "service_name" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.service_name

elseif key == "balancer_ip" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.balancer_ip

elseif key == "balancer_port" then
val = ngx.ctx.api_ctx and ngx.ctx.api_ctx.balancer_port

else
val = get_var(key, t._request)
end

if val ~= nil and not no_cacheable_var_names[key] then
t._cache[key] = val
end

return val
end,

__newindex = function(t, key, val)
if ngx_var_names[key] then
ngx_var[key] = val
end

-- log.info("key: ", key, " new val: ", val)
t._cache[key] = val
end,
}

function _M.set_vars_meta(ctx)
local var = tablepool.fetch("ctx_var", 0, 32)
if not var._cache then
var._cache = {}
end

var._request = get_request()
setmetatable(var, mt)
ctx.var = var
end

function _M.release_vars(ctx)
if ctx.var == nil then
return
end

core_tab.clear(ctx.var._cache)
tablepool.release("ctx_var", ctx.var, true)
ctx.var = nil
end

end -- do


return _M

简单理一下函数框架

  • parse_graphql(ctx)
  • get_parsed_graphql()
  • do
    • var_methods
    • no_cacheable_var_names
    • ngx_var_names
    • mt
      • __index = function(t, key)
      • __newindex = function(t, key, val)
  • _M.set_vars_meta
  • _M.release_vars

然后中有一部分代码可以从 APISIX 的官方一个源码文档里得到学习。

地址为:请求生命周期

开始工作

我的第一版计划

  1. 向上游提交 json 格式的 PR
    1. 上游 PR 通过后,再进行 APISIX 的 issue 修复。
  2. APISIX 中只要对上游的函数进行使用,并输出报错结果就行。

大佬思路

来自APISIX PMC zexuan

大概意思就是,把 json 在APISIX 里解码成 query 字段,然后再将其query 喂给 graphql-lua。

我们并不需要支持 operationName、variable这些功能。

这个思路贼简单,那我为啥想不到呢?

轻微反思,是因为有点“眼高手低”处理实际问题的能力待加强。慢慢学习吧

有个调试问题没解决好,离谱,得加速了。

2022年2月11日的工作

  1. 找到需要更改的代码范围,将 graphql-lua 中的 parse.lua 代码理解清楚。
  2. ctx.lua 代码理解清楚。
  3. 确定思路

2022年2月14日的工作

  1. 完成测试框架的搭建

2022年2月15日的工作

  1. 成功跑通测试框架
  2. 开始正式开发,将问题锁定在具体的部分

问题解决需要在这里添加代码 需要添加代码的地方

很明显,当我从终端扫入一个 body ,它的内容可能是这样的。

2022/02/15 15:31:09 [info] 338683#338683: *77846 [lua] ctx.lua:59: parse_graphql(): booody: query getRepo {owner {name}repo {created}}, client: 127.0.0.1, server: _, request: "POST /graphql HTTP/1.1", host: "127.0.0.1:9080"

这对照了这样的请求:

curl -H 'content-type: application/graphql' -X POST http://127.0.0.1:9080/graphql -d 'query getRepo {owner {name}repo {created}}'

也可以是这样的:

2022/02/15 15:32:55 [info] 338682#338682: *84824 [lua] ctx.lua:59: parse_graphql(): booody: {"query":"query getUser{getUser{name age}}","variables":null}, client: 127.0.0.1, server: _, request: "POST /graphql HTTP/1.1", host: "127.0.0.1:9080"

这对照了这样的请求:

curl 'http://127.0.0.1:9080/graphql' \
-H 'Content-Type: application/json' \
-H 'Accept: */*' \
--data-raw '{"query":"query getUser{getUser{name age}}","variables":null}' \
--compressed

当然,第一个请求就是目前 APISIX 能够处理的 query 格式的 graphql 语句,第二个请求是目前 APISIX 不能够处理的 json 格式的 graphql 语句。

而我需要做的事情,就是把 json 格式转换为 query 格式,既然确认了,就开始做,寻找 lua 转换格式的方法。

· 8 min read
CheverJohn

初始配置篇

我想用ubuntu(based RaspberryPi 4)尝试做一段开发环境

安装

我选择树莓派官方的安装器

树莓派安装界面安装ubuntu

图1. 树莓派安装界面安装Ubuntu中

配置

等这个界面安装成功,先不要急插入树莓派!!!我们先配置一些参数。打开资源管理器,找到启动盘system-boot(F:)

Ubuntu启动盘的位置

图2. 资源管理器里Ubuntu启动盘的位置

然后打开system-boot(F:),我们可以看到如下图所示的文件夹列表

两个配置文件位置

图3. 两个配置文件的具体位置

我们需要注意的是config.txtnetwork-config这两个文件,第一个可以用来调整我树莓派连接7寸显示屏的分辨率参数。第二个文件用来配置树莓派ubuntu连WiFi的能力。

连接网络

树莓派上的Ubuntu该如何连接网络呢?其实官方网站文档都说的很清楚了

我们只需要将文件中一些注释解除就可以了。

网络配置文件

图4.上图是文件原先的样子

下面开始正式配置,可以看到其中TP-LINK_A826即我要连接的WiFi SSIDpassword自然就是该wifi的密码啦。

网络配置详情

图5. 网络配置文件最初始的样子

这边有一个小提示,当我们修改完配置文件后,启动树莓派还是会遇到无法正常联网的情况,那这个时候只需要重启即可,这一块应该是有某些配置文件没有启动,期待有时间的时候,我可以去研究研究看看。

七寸屏幕分辨率

既然已经配置好了配置文件,那我们接下来得把树莓派连接七寸显示器分辨率异常的问题解决一下咯。

首先打开config.txt文件,然后按照下图在文件末尾添加

disable_overscan=1
hdmi_force_hotplug=1 # 强制树莓派使用HDMI端口,即使树莓派没有检测到显示器连接仍然使用HDMI端口。
#该值为0时允许树莓派尝试检测显示器,当该值为1时,强制树莓派使用HDMI。
hdmi_drive=2 # 可以使用该配置项来改变HDMI端口的电压输出:
# 1-DVI输出电压。该模式下,HDMI输出中不包含音频信号。
# 2-HDMI输出电压。该模式下,HDMI输出中包含音频信号。
hdmi_group=2 # 决定的分辨率
# DMT分辨率是hdmi_group=2,计算机显示器使用的分辨率;hdmi_group=1是CEA分辨率 ,CEA规定的电视规格分辨率
hdmi_mode=4

6

图6. 添加完配置信息之后的config.txt

7

图7. 是我最终成功启动树莓派Ubuntu的样子

root用户

当我正常启动了树莓派Ubuntu之后,其实就会遇到两个问题

  1. root账号和ubuntu账号密码不知道
  2. 无法通过ssh工具远程登录root账户

当然第一个问题其实是ubuntu约定成俗的东西。ubuntu在没有设置root账户密码的前提下,每次登录系统密码都是随机生成的。而ubuntu账号的密码默认就是ubuntu,牢记!然后还会要求你创建ubuntu账号的新密码,这边我设计成了我家路由器管理员密码,over。

8

图8. 发现密码不对劲,怎么都无法正常登录

那我们的root账号密码该怎么设立呢? 其实只需要我们使用ubuntu账号修改密码即可

sudo passwd root

然后输入你的新密码即可。

9

图9. 按照方法解决了问题

登录之后配置镜像源

这边需要注意的是,我们是arm架构的ubuntu系统,要在清华源上选择arm架构的镜像源,切记。

10清华镜像源

图10. 根据清华源官网上arm版本配置镜像源

配置镜像源的详细过程就不用多说了,百度一下你就知道。

大功告成!

以上便是在树莓派(RaspberryPi4)中第一次安装ubuntu20.04.3版本的一系列操作。

其中遇到的很多问题在一开始是真的难受,就比如说网络配置,我有上官网看文档的习惯,可以第一次看到官网的配置我也愣是好一会儿没有解决(官网文档在此)。最终呢,我是直接去看了ubuntu系统的启动盘的配置文件,在这个文件里才最终发现,其实我只要解除注释,就可以解决问题了。还有之前各种文章介绍的方法,是真的难以理解啊。比如这篇文章,我直接拉出来鞭尸,什么文章啊这,直接在关键地址配置了两个双引号,我咋知道具体是什么???写上一个真实案例又不会令别人蹭到你家WiFi,再说你可以改密码啊这。反正十分地令我生气。

气死我了气死我了,刚刚发现一篇很好的文章,居然在我写完之后,淦,非常地淦!

文章地址附下:https://mrxiuxing.com/posts/2f81a42d.html

然后也没遇到啥问题了。就这样,解散!

如果需要重新配置网络

当然你可以选择根据上面推荐的很不错的文档教程,一步一步去做。

ubuntu 的网络配置文件地址在 /etc/netplan/ 中。

进入到配置目录中,你可以看到有一个叫做 50-cloud-init.yaml 的文件名:

root@ubuntu:/etc/netplan# ls -la
total 16
drwxr-xr-x 2 root root 4096 Mar 1 05:02 .
drwxr-xr-x 98 root root 4096 Feb 24 06:08 ..
-rw-r--r-- 1 root root 822 Mar 1 05:02 50-cloud-init.yaml

查看其中,将网络根据自己的需求进行配置,你想 dhcp 还是 static 都可以。

最后使用下面命令让配置生效:

sudo netplan --debug apply

然后网络就配好了,over!

· 4 min read
CheverJohn

讲真为什么我会遇到这一块的问题呢?主要还是不熟悉开发流程。 虽然我已经安装好了APISIX,且APISIX的基本内容我都有所了解了。 可是在我实操过程中,还是遇到了很多问题,当然最终发现其实都是基本环境没做好(没有上游服务器端口应该算是基本环境吧?)

开干!

淦,拖了好久了,开始!——2022年2月13日

其实就是给 APISIX 的上游( upstream )添加一个服务器,这里边讨巧选择了 OpenResty。

首先我们已经按照 APISIX 的前置教程安装好了 OpenResty 了,这个必须先确定下来。

安装命令如下:

# 添加 OpenResty 源
sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

# 安装 OpenResty 和 编译工具
sudo yum install -y openresty curl git gcc openresty-openssl111-devel unzip pcre pcre-devel

# 安装 LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -

然后这边再强化一下观念,安装之前本地的代理呀、基本软件(如 git、gcc、unzip等)都要先配置好!

然后我们本地的 OpenResty 的地址可以通过以下命令找回:

OpenResty 的位置

开始配置

跟配置 NGINX 一样

cd /usr/local/openresty/nginx/conf/vhost/1980.conf

首先你先在 conf 文件夹里创建 vhost 文件夹,然后在 /usr/local/openresty/nginx/conf/nginx.conf 文件最下面添加。

添加位置如图

NGINX 文件配置

然后添加如下内容

server {
listen 1980;
access_log logs/access-1980.log main;
error_log logs/error.log;
location / {
content_by_lua_block {
ngx.header["Content-Type"] = "text/html"
local headers = ngx.req.get_headers()
ngx.say("---Headers")
for k, v in pairs(headers) do
ngx.say(k .. ":" .. v)
end

local args = ngx.req.get_uri_args()
ngx.say("---Args")
for k, v in pairs(args) do
ngx.say(k .. ":" .. v)
end

ngx.say("---URI")
ngx.say(ngx.var.uri)

ngx.say("---Service Node")
ngx.say("Ubuntu-DEV-1980")
}
}
}

如图 1980 配置文件内容以及文件树

然后就直接

openresty

启动 1980 服务器即可。

可以看到后端端口,基本上应该打开的都打开咯!

所有端口

来一套基本操作

进行一套基本操作,来试试 APISIX 哈

使用 GraphQL 的配置请求说明问题

命令来自于下面的链接:https://www.cheverjohn.xyz/blog/%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4_graphql%E5%9C%A8APISIX%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8

实现配置 GraphQL 在 APISIX 中

配置

然后发出请求

请求

如此以来,我就配置好了我的一系列测试,新春快乐!

· 12 min read
CheverJohn

本篇博客第一部分受到了这篇博文的启发。

TL; DR

将结论写在前头

事实上,为什么我们很多人在接触一个新的项目时候会遇到各种各样的坑呢?

根据这一次的经历来看,其中的主要原因还是在于本地部署环境的不完备。本次踩坑经历,其实问题就是在 git 啦、gcc 啦等之类看似很常见的东西,实际并没有配置好,然后咱们的项目文档书写者呢,默认了你已经完全配置好这些基本的东西了。唉,但是谁能想到大多数人都会是在虚拟机、wsl、docker上配置,看来 docker 其实更具有实用性,可以当做乐高组件一样,什么时候想用哪几个,直接拼凑起来,就是一个了,不扯远了。

这边先说清楚成功部署APISIX项目,系统需要具备的最基本的东西:

  • git的安装
    • 与Github进行ssh连接得做好
    • git 代理得做好
  • 本地的ssh公钥密钥得有(具体查看.ssh文件夹)
  • centos7应该安装的基本库
    • wget
    • unzip
    • git
    • gcc
    • yum update(重要!!!)

第一部分:安装

安装 APISIX 运行环境依赖

基本方法内容来自于官方文档;

安装 etcd

命令:

wget https://github.com/etcd-io/etcd/releases/download/v3.4.13/etcd-v3.4.13-linux-amd64.tar.gz
tar -xvf etcd-v3.4.13-linux-amd64.tar.gz && \
cd etcd-v3.4.13-linux-amd64 && \
sudo cp -a etcd etcdctl /usr/bin/

安装 OpenResty

命令:

sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

# 安装 OpenResty 和 编译工具
sudo yum install -y openresty curl git gcc openresty-openssl111-devel unzip pcre pcre-devel

# 安装 LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -

然后才能正常启动 etcd

nohup etcd &

第二部分:踩坑

问题一:

LUAROCKS_1

[root@MiWiFi-R4CM-srv apisix-2.10.3]# LUAROCKS_SERVER=https://luarocks.cn make deps
/bin/bash: luarocks: command not found
WARN: You're not using LuaRocks 3.x, please add the following items to your LuaRocks config file:
variables = {
OPENSSL_LIBDIR=/usr/local/openresty/openssl111/lib
OPENSSL_INCDIR=/usr/local/openresty/openssl111/include
}
luarocks install rockspec/apisix-master-0.rockspec --tree=deps --only-deps --local --server https://luarocks.cn
/bin/bash: luarocks: command not found
make: *** [deps] Error 127
[root@MiWiFi-R4CM-srv apisix-2.10.3]# ^C

解决方法

curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -

问题二(接问题一):

当运行了上面的命令后,又出现新的问题,看来是治标不治本啊

Solved_crul_by_installing_sth

[root@MiWiFi-R4CM-srv apisix-2.10.3]# curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -
+ '[' -z ']'
+ OPENRESTY_PREFIX=/usr/local/openresty
+ LUAROCKS_VER=3.8.0
+ wget https://github.com/luarocks/luarocks/archive/v3.8.0.tar.gz
--2022-01-18 04:53:17-- https://github.com/luarocks/luarocks/archive/v3.8.0.tar.gz
Resolving github.com (github.com)... 20.205.243.166
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://codeload.github.com/luarocks/luarocks/tar.gz/v3.8.0 [following]
--2022-01-18 04:53:18-- https://codeload.github.com/luarocks/luarocks/tar.gz/v3.8.0
Resolving codeload.github.com (codeload.github.com)... 20.205.243.165
Connecting to codeload.github.com (codeload.github.com)|20.205.243.165|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5389112 (5.1M) [application/x-gzip]
Saving to: ‘v3.8.0.tar.gz’

100%[====================================================================================================================================================================>] 5,389,112 1.71MB/s in 3.0s

2022-01-18 04:53:22 (1.71 MB/s) - ‘v3.8.0.tar.gz’ saved [5389112/5389112]

+ tar -xf v3.8.0.tar.gz
+ cd luarocks-3.8.0
+ OR_BIN=/usr/local/openresty/bin/openresty
++ /usr/local/openresty/bin/openresty -v
++ awk -F / '{print $2}'
++ awk -F . '{print $1"."$2}'
+ OR_VER=1.19
+ [[ -e /usr/local/openresty/bin/openresty ]]
+ [[ 1.19 == 1.19 ]]
+ WITH_LUA_OPT=--with-lua=/usr/local/openresty/luajit
+ ./configure --with-lua=/usr/local/openresty/luajit
+ cat build.log

Configuring LuaRocks version 3.8.0...

Lua version detected: 5.1
Lua interpreter found: /usr/local/openresty/luajit/bin/luajit
lua.h found: /usr/local/openresty/luajit/include/luajit-2.1/lua.h
Could not find 'unzip'.
Make sure it is installed and available in your PATH.

configure failed.

+ exit 1
[root@MiWiFi-R4CM-srv apisix-2.10.3]# sudo yum install wget sudo unzip
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.163.com
* updates: mirrors.163.com

解决方法:

sudo yum install wget sudo unzip

问题三(接问题二):

继续运行

[root@MiWiFi-R4CM-srv apisix-2.10.3]# curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -

发现还有问题

install_gcc

解决方法:

yum -y install gcc

直接解决了问题

[root@MiWiFi-R4CM-srv apisix-2.10.3]# yum -y install gcc
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.163.com
* updates: mirrors.163.com
Resolving Dependencies
--> Running transaction check
---> Package gcc.x86_64 0:4.8.5-44.el7 will be installed
--> Processing Dependency: cpp = 4.8.5-44.el7 for package: gcc-4.8.5-44.el7.x86_64
--> Processing Dependency: glibc-devel >= 2.2.90-12 for package: gcc-4.8.5-44.el7.x86_64
--> Processing Dependency: libmpfr.so.4()(64bit) for package: gcc-4.8.5-44.el7.x86_64
--> Processing Dependency: libmpc.so.3()(64bit) for package: gcc-4.8.5-44.el7.x86_64
--> Running transaction check
---> Package cpp.x86_64 0:4.8.5-44.el7 will be installed
---> Package glibc-devel.x86_64 0:2.17-325.el7_9 will be installed
--> Processing Dependency: glibc-headers = 2.17-325.el7_9 for package: glibc-devel-2.17-325.el7_9.x86_64
--> Processing Dependency: glibc = 2.17-325.el7_9 for package: glibc-devel-2.17-325.el7_9.x86_64
--> Processing Dependency: glibc-headers for package: glibc-devel-2.17-325.el7_9.x86_64
---> Package libmpc.x86_64 0:1.0.1-3.el7 will be installed
---> Package mpfr.x86_64 0:3.1.1-4.el7 will be installed
--> Running transaction check
---> Package glibc.x86_64 0:2.17-317.el7 will be updated
--> Processing Dependency: glibc = 2.17-317.el7 for package: glibc-common-2.17-317.el7.x86_64
---> Package glibc.x86_64 0:2.17-325.el7_9 will be an update
---> Package glibc-headers.x86_64 0:2.17-325.el7_9 will be installed
--> Processing Dependency: kernel-headers >= 2.2.1 for package: glibc-headers-2.17-325.el7_9.x86_64
--> Processing Dependency: kernel-headers for package: glibc-headers-2.17-325.el7_9.x86_64
--> Running transaction check
---> Package glibc-common.x86_64 0:2.17-317.el7 will be updated
---> Package glibc-common.x86_64 0:2.17-325.el7_9 will be an update
---> Package kernel-headers.x86_64 0:3.10.0-1160.49.1.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================================================================================================================================
Package Arch Version Repository Size
==============================================================================================================================================================================================================
Installing:
gcc x86_64 4.8.5-44.el7 base 16 M
Installing for dependencies:
cpp x86_64 4.8.5-44.el7 base 5.9 M
glibc-devel x86_64 2.17-325.el7_9 updates 1.1 M
glibc-headers x86_64 2.17-325.el7_9 updates 691 k
kernel-headers x86_64 3.10.0-1160.49.1.el7 updates 9.0 M
libmpc x86_64 1.0.1-3.el7 base 51 k
mpfr x86_64 3.1.1-4.el7 base 203 k
Updating for dependencies:
glibc x86_64 2.17-325.el7_9 updates 3.6 M
glibc-common x86_64 2.17-325.el7_9 updates 12 M

Transaction Summary
==============================================================================================================================================================================================================
Install 1 Package (+6 Dependent packages)
Upgrade ( 2 Dependent packages)

Total download size: 48 M
Downloading packages:
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.
(1/9): cpp-4.8.5-44.el7.x86_64.rpm | 5.9 MB 00:00:04
(2/9): glibc-headers-2.17-325.el7_9.x86_64.rpm | 691 kB 00:00:00
(3/9): glibc-devel-2.17-325.el7_9.x86_64.rpm | 1.1 MB 00:00:05
(4/9): libmpc-1.0.1-3.el7.x86_64.rpm | 51 kB 00:00:00
(5/9): mpfr-3.1.1-4.el7.x86_64.rpm | 203 kB 00:00:00
(6/9): glibc-common-2.17-325.el7_9.x86_64.rpm | 12 MB 00:00:08
(7/9): gcc-4.8.5-44.el7.x86_64.rpm | 16 MB 00:00:08
(8/9): kernel-headers-3.10.0-1160.49.1.el7.x86_64.rpm | 9.0 MB 00:00:04
(9/9): glibc-2.17-325.el7_9.x86_64.rpm | 3.6 MB 00:00:10
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 4.7 MB/s | 48 MB 00:00:10
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Updating : glibc-2.17-325.el7_9.x86_64 1/11
Updating : glibc-common-2.17-325.el7_9.x86_64 2/11
Installing : mpfr-3.1.1-4.el7.x86_64 3/11
Installing : libmpc-1.0.1-3.el7.x86_64 4/11
Installing : cpp-4.8.5-44.el7.x86_64 5/11
Installing : kernel-headers-3.10.0-1160.49.1.el7.x86_64 6/11
Installing : glibc-headers-2.17-325.el7_9.x86_64 7/11
Installing : glibc-devel-2.17-325.el7_9.x86_64 8/11
Installing : gcc-4.8.5-44.el7.x86_64 9/11
Cleanup : glibc-2.17-317.el7.x86_64 10/11
Cleanup : glibc-common-2.17-317.el7.x86_64 11/11
Verifying : mpfr-3.1.1-4.el7.x86_64 1/11
Verifying : glibc-devel-2.17-325.el7_9.x86_64 2/11
Verifying : gcc-4.8.5-44.el7.x86_64 3/11
Verifying : glibc-headers-2.17-325.el7_9.x86_64 4/11
Verifying : kernel-headers-3.10.0-1160.49.1.el7.x86_64 5/11
Verifying : libmpc-1.0.1-3.el7.x86_64 6/11
Verifying : glibc-common-2.17-325.el7_9.x86_64 7/11
Verifying : glibc-2.17-325.el7_9.x86_64 8/11
Verifying : cpp-4.8.5-44.el7.x86_64 9/11
Verifying : glibc-2.17-317.el7.x86_64 10/11
Verifying : glibc-common-2.17-317.el7.x86_64 11/11

Installed:
gcc.x86_64 0:4.8.5-44.el7

Dependency Installed:
cpp.x86_64 0:4.8.5-44.el7 glibc-devel.x86_64 0:2.17-325.el7_9 glibc-headers.x86_64 0:2.17-325.el7_9 kernel-headers.x86_64 0:3.10.0-1160.49.1.el7 libmpc.x86_64 0:1.0.1-3.el7 mpfr.x86_64 0:3.1.1-4.el7

Dependency Updated:
glibc.x86_64 0:2.17-325.el7_9 glibc-common.x86_64 0:2.17-325.el7_9

Complete!

Complete_by_install_gcc

问题四(搁浅中......):

这边的LUAROCKS是针对于

开始LUAROCKS_SERVER......

[root@MiWiFi-R4CM-srv apisix-2.10.3]# LUAROCKS_SERVER=https://luarocks.cn make deps

爆出问题

solve

分析问题:

[root@MiWiFi-R4CM-srv apisix-2.10.3]# LUAROCKS_SERVER=https://luarocks.cn make deps
…………………………………………………………………………………………………………………………………………………………………………
lua-resty-dns-client 5.2.0-1 depends on luaxxhash >= 1.0 (not installed)
Installing https://luarocks.cn/luaxxhash-1.0.0-1.rockspec

Error: Failed installing dependency: https://luarocks.cn/lua-resty-dns-client-5.2.0-1.src.rock - Failed installing dependency: https://luarocks.cn/luaxxhash-1.0.0-1.rockspec - 'git' program not found. Make sure Git is installed and is available in your PATH (or you may want to edit the 'variables.GIT' value in file '/root/.luarocks/config-5.1.lua')
make: *** [deps] Error 1
[root@MiWiFi-R4CM-srv apisix-2.10.3]# yum install -y git

很明显就是没有安装配置好git嘛

config_git

lua-resty-dns-client 5.2.0-1 depends on lua >= 5.1, < 5.4 (5.1-1 provided by VM)
lua-resty-dns-client 5.2.0-1 depends on penlight ~> 1 (1.12.0-1 installed)
lua-resty-dns-client 5.2.0-1 depends on lrandom (20180729-1 installed)
lua-resty-dns-client 5.2.0-1 depends on lua-resty-timer ~> 1 (1.1.0-1 installed)
lua-resty-dns-client 5.2.0-1 depends on binaryheap >= 0.4 (0.4-1 installed)
lua-resty-dns-client 5.2.0-1 depends on luaxxhash >= 1.0 (not installed)
Installing https://luarocks.cn/luaxxhash-1.0.0-1.rockspec
Cloning into 'luaxxhash'...
error: RPC failed; result=35, HTTP code = 0
fatal: The remote end hung up unexpectedly

Error: Failed installing dependency: https://luarocks.cn/lua-resty-dns-client-5.2.0-1.src.rock - Failed installing dependency: https://luarocks.cn/luaxxhash-1.0.0-1.rockspec - Failed cloning git repository.
make: *** [deps] Error 1
[root@MiWiFi-R4CM-srv apisix-2.10.3]# ls
apisix bin CHANGELOG.md CODE_OF_CONDUCT.md CODE_STYLE.md conf CONTRIBUTING.md deps LICENSE Makefile NOTICE powered-by.md README.md rockspec v3.8.0.tar.gz v3.8.0.tar.gz.1
[root@MiWiFi-R4CM-srv apisix-2.10.3]#
[root@MiWiFi-R4CM-srv apisix-2.10.3]# cd ..
[root@MiWiFi-R4CM-srv api7]# ls
apache-apisix-2.10.3-src.tgz apisix-2.10.3
[root@MiWiFi-R4CM-srv api7]# git clone git@github.com:Chever-John/JohnChever-Blog.git
Cloning into 'JohnChever-Blog'...
The authenticity of host 'github.com (20.205.243.166)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
ECDSA key fingerprint is MD5:7b:99:81:1e:4c:91:a5:0d:5a:2e:2e:80:13:3f:24:ca.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,20.205.243.166' (ECDSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
[root@MiWiFi-R4CM-srv api7]# git clone git@github.com:Chever-John/JohnChever-Blog.git
Cloning into 'JohnChever-Blog'...
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
[root@MiWiFi-R4CM-srv api7]# git config --global user.name "CheverJohn"
[root@MiWiFi-R4CM-srv api7]# git config --global user.email "cheverjonathan@gmail.com"
[root@MiWiFi-R4CM-srv api7]# git config --list
user.name=CheverJohn
user.email=cheverjonathan@gmail.com
[root@MiWiFi-R4CM-srv api7]# ssh-keygen -t rsa -C "cheverjonathan@gmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:XVvMrYv9c92MVJm8CMUmZA44WgYv+atEOydMkpWc0I8 cheverjonathan@gmail.com
The key's randomart image is:
+---[RSA 2048]----+
| .... ...o. |
| o.== +. * . |
| B*.. .= = +|
| oEo. . o o =.|
| o o .S . o o..|
| = . . +.o |
| * o ..ooo|
| . = .o=|
| . +|
+----[SHA256]-----+
[root@MiWiFi-R4CM-srv api7]# cat /root/.ssh
cat: /root/.ssh: Is a directory
[root@MiWiFi-R4CM-srv api7]# ls
apache-apisix-2.10.3-src.tgz apisix-2.10.3
[root@MiWiFi-R4CM-srv api7]# cd /root/.ssh
[root@MiWiFi-R4CM-srv .ssh]# ls
id_rsa id_rsa.pub known_hosts
[root@MiWiFi-R4CM-srv .ssh]# cat id_rsa.pub
接下来显示就是生成的ssh密钥了,将其复制到github上的ssh里即可

继续LUAROCKS_SERVER......

LUAROCKS_SERVER=https://luarocks.cn make deps

还是出现了问题

maybe_git_proxy

怀疑是git代理的问题!!!

这边开始暂时不搞apisix中的LUAROCKS了,开始按照官网的需求准备

未解决!!!

问题五:前提需求准备中的wget问题

然后遇到了wget问题

如果使用wget的话,会出现一个

just_yum_update

遇到Unable to establish SSL connection的报错

这个时候,只需要轻轻yum update即可,原因是未更新前的centos里的库大部分是老旧的,特别是导致这个问题的openssl。

此处(指yum update)收到了该链接的灵感。

当我们yum update之后,即可成功

然后运行wget,至此wget https://github.com/etcd-io/etcd/releases/download/v3.4.13/etcd-v3.4.13-linux-amd64.tar.gz完美解决,结束了。

成功结束的样子

finish

问题六:继续回到问题四

LUAROCKS_SERVER继续在apisix-2.10.3文件中进行运行

// 遇到问题!
apisix master-0 depends on lua-resty-ngxvar 0.5.2 (not installed)
Installing https://luarocks.cn/lua-resty-ngxvar-0.5.2-0.rockspec
Cloning into 'lua-var-nginx-module'...
fatal: unable to access 'https://github.com/api7/lua-var-nginx-module/': Encountered end of file

Error: Failed installing dependency: https://luarocks.cn/lua-resty-ngxvar-0.5.2-0.rockspec - Failed cloning git repository.
make: *** [deps] Error 1
[root@MiWiFi-R4CM-srv apisix-2.10.3]#

完成etcd的安装

finish_etcd

这边根据链接讲的东西从而进行etcd的安装。

All Done

上一张证明自己All Done的截图照片

All-Done-Solved_Problems

试试证明确实使用git proxy代理好,一下子就能解决所有问题了。

git_proxy

列出一些算是对我有所帮助的链接地址吧

https://www.mihu.live/archives/208/ https://zhuanlan.zhihu.com/p/120038973

晚上再来把文字搞好看一点

请忽略的etcd文件夹目录,刚刚运行起etcd了。so就急匆匆curl咯,根据这处链接及其提供的命令和结果,得以判断咱们的Apache APISIX是否已经成功启动。

· 2 min read
CheverJohn

本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net

现象说明
在安装 CentOS 系统后,有可能出现无法联网的问题,虚拟机中的网络配置并没有问题,而系统却无法联网, 也 ping 不同。

原因描述
CentOS 默认开机不启动网络,因此需要对网络进行配置,开启网络开机启动。

解决方法

  1. 打开终端,使用ip addr命令查看一下网络信息
    findMyNIC
    图中圈出的是系统网络名称,我们稍后会用到它,有的系统是 ens33,有的是 eth0 等
  2. 切换至 root 用户,输入命令vi /etc/sysconfig/network-scripts/ifcfg-<系统网络名称>,我的是 eth33,所以输入vi /etc/sysconfig/network-scripts/ifcfg-ens33命令
    login
  3. 进入 vi 界面,可以看到,ONBOOT 的值是 no
    changeConfig
  4. 将 ONBOOT 的值改为 yes(不会使用 vi 的可以百度一下,很容易上手的)
    afterChange
  5. 保存后退出,重启系统(可以reboot命令重启)。重启完成后,可以使用浏览器打开个网页看看,也可以使用ping命令测试网络连通性
    testNetwork

· 26 min read
CheverJohn

TL; DR :)

文章内容描述

本篇文章主要聚焦一个实操点:虚拟机(VMware)中Centos-7系统的网络配置以及如何从宿主机使用功能ssh工具连接到虚拟机(VMware)中的Centos-7系统。

本篇文章主要涉及到的原理知识为:

  • 计算机网络中的子网掩码网关是什么
  • VMware主要的网络通信方式:桥接、NAT

所以,阅读完本篇文章,你将会收获......

计算机网络中两个基础知识——子网掩码网关,以及VMware的网络方案架构

感慨啊~真的是好久没有接触这个东西,然后又因为我的计算机网络知识基础也太不牢固了叭,居然老是忘记配置centos的子网掩码和 网关,就用这篇文章好好的巩固一下吧。

看是解决不了问题的,要实操! 韶光易逝,劝君惜取少年时! ——笔者(CheverJohn)疯狂寄语hhhh

实际操作

本地环境说明

windows version: 21H1(OS Build 19043.1415)

远程连接工具: Mobaxterm

安装centos(主要是指网络配置)

我们在安装Centos的时候,会经历一个网络环境配置的问题。

当然安装Centos的过程我就不讲了,这边重点还是给Centos进行网络配置的过程。

VMware中的linux网络配置从VMware本身层面来讲,有三种

1. Bridged   桥接模式
2. NAT NAT模式
3. Host-only

就先这么叫着,我这边介绍一种方法——Bridged 桥接模式(我认为很简单的方法)。

桥接模式(wifi下也可以用)

简单介绍一下桥接模式

桥接网络是指本地物理网卡和虚拟网卡通过VMnet0虚拟交换机进行桥接,物理网卡和虚拟网卡在拓扑图上处于同等地位,那么物理网卡和虚拟网卡就相当于处于同一个网段,虚拟交换机就相当于一台现实网络中的交换机,所以两个网卡的IP地址也要设置为同一网段。

所以当我们要在局域网使用虚拟机,对局域网其他pc提供服务时,例如提供ftp,提供ssh,提供http服务,那么就要选择桥接模式。

例如大学宿舍里有一个路由器,宿舍里四个人连接这个路由器,路由器的wanip就不理会了,这个ip是动态获取的,而lanip默认是192.168.1.1,子网掩码是255.255.255.0。而其他四个人是自动获取ip,假设四个人的ip是:

A:192.168.1.100/255.255.255.0, B:192.168.1.101/255.255.255.0, C:192.168.1.102/255.255.255.0, D:192.168.1.103/255.255.255.0

那么虚拟机的ip可以设置的ip地址是192.168.1.2-192.168.1.99,192.168.1.104-192.168.1.254(网络地址全0和全1的除外,再除去ABCD四个人的ip地址)

那么虚拟机的ip地址可以设置为192.168.1.98/255.255.255.0,设置了这个ip地址,ABCD这四个人就可以通过192.168.1.98访问虚拟机了,如果虚拟机需要上外网,那么还需要配置虚拟机的路由地址,就是192.168.1.1了,这样,虚拟机就可以上外网了,但是,上网我们一般是通过域名去访问外网的,所以我们还需要为虚拟机配置一个dns服务器,我们可以简单点,把dns服务器地址配置为google的dns服务器:8.8.8.8,到此,虚拟机就可以上网了。

来源自链接

具体的原理见下面的详细讲解

配置桥接模式

emmmmm,还是看B站CodeSheep的视频叭,因为我发现我的配置好了,截图好像发出来不是桥接模式的截图,是NAT的,就很迷。

固定住centos的IP地址

当我们刚安装好,centos的网卡配置文件有几项是关闭的,我们需要打开一下,然后设置成如下图所示:

centos的网卡配置文件

没错这边,我的固定ip地址为192.168.2.233,然后我为其配置的网关为192.168.2.1。

至于我为什么这么配置,还请看下面的原理讲解。

然后配置完成后,就得重启网卡咯

# centos7
systemctl restart network

PS: 这边其实还需要注意一点,因为选择了桥接模式,那么我们的虚拟机其实是和宿主机是在同一个网段的,我宿主机的IP地址是192.168.2.228,然后我的虚拟机里的IP地址是192.168.2.233,前三个网段很明显,我设置的静态IP很明显。

测试是否ping通

在虚拟机里ping宿主机

虚拟机ping宿主机

在宿主机里ping虚拟机

宿主机ping虚拟机

原理讲述

VMware网络连接原理

来源

提前声明,本部分内容大部分来自于官方文档

官方文档,yyds,永远的神!

此外我加入了我个人的理解,就是这样。

Bridged Networking(桥接网络)

原理讲解

首先介绍的就是我们的桥接网络配置。

先干上一大段来自官方文档的说明

When you install Workstation Pro on a Windows or Linux host system, a bridged network (VMnet0) is set up for you. Bridged networking connects a virtual machine to a network by using the network adapter on the host system. If the host system is on a network, bridged networking is often the easiest way to give the virtual machine access to that network.

With bridged networking, the virtual network adapter in the virtual machine connects to a physical network adapter in the host system. The host network adapter enables the virtual machine to connect to the LAN that the host system uses. Bridged networking works with both wired and wireless host network adapters.

Bridged networking configures the virtual machine as a unique identity on the network, separate from and unrelated to the host system. The virtual machine is a full participant in the network. It has access to other machines on the network, and other machines on the network can contact it as if it were a physical computer on the network.

看到大段英文不要怕哈,要么勇敢地读下去,要么直接转去百度翻译hhhh

上面来自官方文档的开场白,主要说的就是桥接模式是一种最简单的联网模式。而且使用了桥接模式之后,虚拟机就相当于独立的一台物理机在局域网中(如下图所示),就相当于和宿主机同时连接在了一台网络交换机上的两个不同的端口上。虽然这俩其实都在一台实体的电脑上hhhh,就很神奇是不是。但我想如果你能够理解网卡就相当于一台设备在网络中的“唯一标识“之后,这点就很容易理解啦!

Bridged Networking Configuration

Bridged Networking Configuration

You can view and change the settings for bridged networking on the host system, determine which network adapters to use for bridged networking, and map specific host network adapters to specific virtual switches.

你也可以在主机系统上查看和更改桥接网络的设置,确定使用哪些网络适配器进行桥接网络,并将特定的主机网络适配器映射到特定的虚拟交换机。

唉,就相当于是说在宿主机上进行网卡的相关配置。我命令哪些网卡去做与哪些虚拟机系统相关的操作尔尔。

提供各种玩法

Assigning IP Addresses in a Bridged Networking Environment

A virtual machine must have its own identity on a bridged network. For example, on a TCPIP network, the virtual machine needs its own IP address. Your network administrator can tell you whether IP addresses are available for virtual machines and which networking settings to use in the guest operating system.

虚拟机在桥接网络上必须有自己的标识。例如,在TCPIP网络中,虚拟机需要自己的IP地址。网络管理员可以告诉您虚拟机的IP地址是否可用,以及在客户操作系统中使用哪些网络设置。

我理解哈,如果要让虚拟机的网络能够正常使用,那么就得按照我上头讲的配置(固定系统IP),然后就能跑通啦。

关于这一大段话的详细解释在这个链接我觉得我的理解也没啥问题。

Add a Bridged Network

When you install Workstation Pro on a Windows or Linux host system, a bridged network (VMnet0) is set up for you. If you install Workstation Pro on a host system that has multiple network adapters, you can configure multiple bridged networks.

啊这这这这~总感觉这段是废话,有种那种说了半天还是废话的感觉。。。

Configure Bridged Networking for an Existing Virtual Machine

You can configure bridged networking for an existing virtual machine.[了解更多内容]

emmm,这个我该咋说呢?字面意思啊,你可以为一个已存在的虚拟机配置桥接,自己个点了解更多内容去看叭。

Change VMnet0 Bridged Networking Settings

By default, VMnet0 is set to use auto-bridging mode and is configured to bridge to all active network adapters on the host system. You can use the virtual network editor to change VMnet0 to bridge to one specific host network adapter, or restrict the host network adapters that VMnet0 auto-bridges to. The changes you make affect all virtual machines that use bridged networking on the host system.[了解更多内容]

我们还可以改变VMnet0的设置哦,去和自己想要的宿主机网卡适配器进行配置呢。详情请点击上方链接噻。

Network Address Translation(NAT模式)

原理讲解

字面意思哦,网络地址翻译,大家可以这么理解,相当于一种绑定,键值对的绑定hhhh。拿数据库的东西来理解呢。

首先开始一波官方的自我介绍

When you install Workstation Pro on a Windows or Linux host system, a NAT network (VMnet8) is set up for you. When you use the New Virtual Machine wizard to create a typical virtual machine, the wizard configures the virtual machine to use the default NAT network.

With NAT, a virtual machine does not have its own IP address on the external network. Instead, a separate private network is set up on the host system. In the default configuration, virtual machines get an address on this private network from the virtual DHCP server.

这边开始要出现“真东西”咯,虚拟出一个DHCP server

我直接说 好处:独立出一个DHCP服务器来分配域名,虚拟机不会占用宿主机的IP,不会有IP冲突的风险,当然你的使用程度过少(用到的虚拟机太少,体现不了这种差距) 缺点:内网中的其他人无法和虚拟机通讯(或者说很难进行通信,实际上我还没有成功配置过NAT模式下宿主机与虚拟之间的通信呢)

NAT Configuration

NAT Configuration

The virtual machine and the host system share a single network identity that is not visible on the external network. NAT works by translating the IP addresses of virtual machines in the private network to the IP address of the host system. When a virtual machine sends a request to access a network resource, it appears to the network resource as if the request is coming from the host system.

虚拟机和主机系统共享一个在外部网络中不可见的网络标识。NAT的工作原理是将私有网络中的虚拟机的IP地址转换为主机系统的IP地址。当虚拟机发送访问网络资源的请求时,网络资源会认为这个请求来自主机系统。

NAT 模式主要还是起到了一个翻译的中转站功能,和桥接相比,他比较能够避免跟宿主机抢IP地址。桥接模式可是直接跟宿主机“”IP地址了呢。

The host system has a virtual network adapter on the NAT network. This adapter enables the host system and virtual machines to communicate with each other. The NAT device passes network data between one or more virtual machines and the external network, identifies incoming data packets intended for each virtual machine, and sends them to the correct destination.

主机系统在NAT网络中存在一个虚拟网卡。这个适配器使主机系统和虚拟机能够相互通信。NAT设备负责在一台或多台虚拟机与外部网络之间传递网络数据,识别接收到每个虚拟机的数据包,并将这些数据包发送到正确的目的地。

详细举了个例子解释了NAT的工作能力。

提供各种玩法

Features and Limitations of NAT Configurations

NAT is useful when the number of IP addresses is limited or the host system is connected to the network through a non-Ethernet adapter.[了解更多内容]

当IP地址数量有限或主机系统通过非以太网适配器连接到网络时,NAT很有用

这不就正好呼应了我的开头嘛,NAT不跟宿主机抢IP地址,是位好同志!

Change NAT Settings

You can change the gateway IP address, configure port forwarding, and configure advanced networking settings for NAT networks. [了解更多内容]

您可以修改网关地址、配置端口转发、配置NAT网络的高级组网设置。

自己去探索琢磨叭,我也是新手,不了解呢。

Editing the NAT Configuration File

If you are an advanced user, you can edit the NAT configuration file to modify NAT settings. [了解更多内容]

如果您是高级用户,您可以通过编辑NAT配置文件来修改NAT设置。

这不是废话嘛。没试过,你们加油。

Using NAT with NetLogon

If you use NAT networking in a Windows virtual machine running on a Windows host system, you can use NetLogon to log in to a Windows domain from the virtual machine and access file shares that the WINS server knows.[了解更多内容]

如果在Windows主机系统的Windows虚拟机上使用NAT组网,可以通过NetLogon在虚拟机上登录Windows域,访问WINS服务器知道的文件共享。

确实,能够访问windows,而windows无法访问虚拟机,这个我确实实操过,就挺离谱的。

Specifying Connections from Source Ports Below 1024

If a virtual machine that uses NAT attempts to connect to a server that requires the client to use a source port below 1024, the NAT device must forward the request from a port below 1024. For security reasons, some servers accept connections only from source ports below 1024.[了解更多内容]

如果使用NAT的虚拟机尝试连接服务器,而服务器要求客户端使用1024以下的源端口,NAT设备必须转发1024以下的源端口请求。出于安全原因,一些服务器只接受来自源端口小于1024的连接。

长知识了呢!

Host-Only Networking Configuration

原理讲解

When you install Workstation Pro on a Windows or Linux host system, a host-only network (VMnet1) is set up for you. Host-only networking is useful if you need to set up an isolated virtual network. In a host-only network, the virtual machine and the host virtual network adapter are connected to a private Ethernet network. The network is completely contained within the host system.

当您在Windows或Linux主机系统上安装Workstation Pro时,会为您设置一个仅供主机使用的网络(VMnet1)。如果您需要设置一个隔离的虚拟网络,那么仅供主机使用的网络非常有用。在仅供主机使用的网络中,虚拟机和主机虚拟网卡连接到专用以太网网络。网络完全包含在主机系统中。

The network connection between the virtual machine and the host system is provided by a virtual network adapter that is visible on the host operating system. The virtual DHCP server provides IP addresses on the host-only network.

虚拟机和主机系统之间的网络连接是由主机操作系统上可见的虚拟网络适配器提供的。虚拟DHCP服务器在主机专用网络中提供IP地址。

看了一大段官方的开场白

直接上我的结论:

Host-Only网络配置能实现的网络效果描述如下: 单独的一台机器,全封闭的网络,虚拟机唯一能够访问的就是主机。当然多个虚拟机之间也可以互相访问。如果想要虚拟机上外网则需要主机联网并且网络共享。

Host-Only Networking Configuration

Host-Only Networking Configuration

In the default configuration, a virtual machine in a host-only network cannot connect to the Internet. If you install the proper routing or proxy software on the host system, you can establish a connection between the host virtual network adapter and a physical network adapter on the host system to connect the virtual machine to a Token Ring or other non-Ethernet network.

默认情况下,主机专用网络中的虚拟机不能连接到Internet。如果在主机系统上安装了合适的路由或代理软件,可以在主机虚拟网卡和主机系统的物理网卡之间建立连接,将虚拟机连接到令牌环或其他非以太网网络。

这一块触及到我的盲区了,令牌环emmmm,应该是token连接那一块的,希望以后补充。

On a Windows host computer, you can use host-only networking in combination with the Internet Connection Sharing feature in Windows to allow a virtual machine to use the dial-up networking adapter or other connection to the Internet on the host system. See Microsoft documentation for information on configuring Internet Connection Sharing.

在Windows主机计算机上,您可以结合使用Windows中的Internet连接共享特性,以允许虚拟机使用拨号网络适配器或其他连接到主机系统上的Internet。有关配置Internet连接共享的信息,请参阅Microsoft文档。

我直接直译咯!

提供各种玩法

Add a Host-Only Network

When you install Workstation Pro on a Windows or Linux host system, a host-only network (VMnet1) is set up for you. You might want to configure multiple host-only networks to manage network traffic between virtual machines in specific ways. [了解更多内容]

配置多个Host-Only方式的虚拟机实现共通通讯。

Configure Host-Only Networking for an Existing Virtual Machine

You can configure host-only networking for an existing virtual machine. You can connect a virtual network adapter to the default host-only network (VMnet1) or to a custom host-only network. If a virtual machine has two virtual network adapters, you can connect it to two host-only networks. [了解更多内容]

默认的或自定义的网络。一个虚拟机还可以同时连接至两个Host-Only模式的网络呢。新增玩法,GET!

Set Up Routing Between Two Host-Only Networks

If you are setting up a complex test network that uses virtual machines, you might want to have two independent host-only networks with a router between them. [了解更多内容]

一种Host-Only的应用场景

Avoiding IP Packet Leakage in Host-Only Networks

Each host-only network should be confined to the host system on which it is set up. Packets that virtual machines send on this network should not leak out to a physical network attached to the host system. Packet leakage can occur only if a machine actively forwards packets.[了解更多内容]

每个Host-Only网络应该被限制在它所建立的主机系统中。虚拟机在这个网络上发送的数据包不应该泄漏到连接到主机系统的物理网络上。只有当机器主动转发数据包时,才会发生数据包泄漏。

网络被限制住了噻。非允许,不可以向物理机(宿主机)发送数据包(数据包泄露)

Controlling Routing Information for Host-Only Networks on Linux

A host-only network has a network interface associated with it (vmnet1) that is marked up when the host operating system is booted. Routing server processes that operate on the host operating system automatically discover the host-only network and propagate information on how to reach the network, unless you explicitly configure them not to do so.[了解更多内容]

仅供主机使用的网络有一个与之关联的网络接口(vmnet1),该接口在主机操作系统启动时被标记出来。在主机操作系统上运行的路由服务器进程会自动发现主机专用网络,并传播关于如何到达网络的信息,除非您显式地将它们配置为不这样做。

Using DHCP and DDNS with Host-Only Networking on Linux

The virtual DHCP server in Workstation Pro cannot update a DNS server by using a Dynamic Domain Name Service (DDNS). For this reason, you should use DHCP to supply IP addresses as well as other information, such as the identity of a host running a name server and the nearest router or gateway. [了解更多内容]

“工作站专业版”中的虚拟DHCP服务器无法通过DDNS (Dynamic Domain Name Service)更新DNS服务器。由于这个原因,您应该使用DHCP来提供IP地址以及其他信息,例如运行名称服务器的主机的标识以及最近的路由器或网关。

计网基础知识

唉,太晚了不写了,2022年1月12日00:49:04

放个我颇受感慨,且认为还不错的视频链接叭

https://www.bilibili.com/video/BV1xu411f7UW?spm_id_from=333.1007.top_right_bar_window_history.content.click

yyds,通俗易懂呢!