vagrant 快速上手(基于Debian9)

vagrant 是一款管理虚拟机的软件,我使用它作为分布式开发的环境配置。

Vagrant是 hashicorp 公司的产品,这家公司也非常有名气,主要做数据中心 PaaS 和虚拟化,大名鼎鼎的 Consul 就是他们家的。

这篇文章介绍我在 Debian 9下的的安装过程和一些常用命令,作个备忘。

1. 环境准备

vagrant默认是与virtubox组合使用,在使用之前,要先将两者都安装好:

2. 概念理解

安装完成后就可以正式开始使用了。在使用前,我们要先理解一些 vagrant 的基本概念。

  • Vagrant命令:提前定义一个Vagrantfile文件,便可以通过这个命令行工具启动一个虚拟机

  • Vagrantfile:是用来定义vagrant project的,使用ruby语法,但实际使用我们并不需要了解ruby。

  • Boxes:就是vagrant封装的虚拟机系统,我们也可以基于这些box做自己的系统。

    boxes vagrant拉起虚机的时候会自动下载,如果自动下载速度太慢,也可以手动下载:boxex的下载地址,下载后使用命令 vagrant box add xxx.box 即可。

vagrant up命令会搜索当前文件夹下的Vagrantfile并启动虚机。在虚拟机中会有一个/vagrant目录,这跟Vagrantfile是同一级目录,和宿主机上的目录文件是同步的。

vagrant 还有非常多的概念,这里就不展开了,可以直接看官方文档

  • push
  • plugins
  • providers

我是从 kuma 这个应用过来的,他们有一个完善的vagrant,可以参考学习:

 git clone https://github.com/kumahq/kuma-demo.git
 cd kuma-demo/vagrant
 vagrant up

3. Vagrantfile常用配置

  • 本机与虚拟机同步的目录

    config.vm.synced_folder "d:/workspace", "/workspace"
    
  • 端口转发

    config.vm.network :forwarded_port, guest: 80, host: 8080
    
  • 私网IP设置

    config.vm.network :forwarded_port, guest: 80, host: 8080
    
  • 公网IP设置

    config.vm.network :public_network, ip: “192.168.10.10”
    

4. Vagrant 常用命令

  • vagrant box add NAME URL #添加一个 box
  • vagrant box list #查看本地已添加的 box
  • vagrant box remove NAME virtualbox #删除本地已添加的 box
  • vagrant init NAME 初始化,实质应是创建 Vagrantfile 文件
  • vagrant up 启动虚拟机
  • vagrant destroy 销毁虚拟机
  • vagrant halt 关闭虚拟化开发环境
  • vagrant reload 修改配置文件后,重启虚拟化开发环境
  • vagrant box list 查看当前可用的虚拟化开发环境
  • vagrant box add box-name box-file 添加指定的box环境
  • vagrant box remove box-name 删除指定的box环境
  • vagrant package 当前正在运行的VirtualBox虚拟环境打包成一个可重复使用的box
  • vagrant ssh manage 登陆ssh虚机

5. 我的demo

这是我的 Vagrantfile:

image-20210116142225841

# -*- mode: ruby -*-
# vi: set ft=ruby :

TEST_IP      = "10.180.77.10"
K8S1_CIDR   = "10.181.0.0/16"
K8S2_CIDR   = "10.182.0.0/16"
K8S1_MASTER_IP     = "10.180.0.130"
K8S1_NODE_1_IP     = "10.180.0.131"
K8S1_NODE_2_IP     = "10.180.0.132"

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/bionic64"
  config.vm.provider "virtualbox" do |v|
    v.memory = 2048
    v.cpus = 2
  end

  config.vm.define "test" do |node|
#    node.vm.box = "ubuntu/bionic64"
    node.vm.provider "virtualbox" do |v|
      v.memory = 512
      v.cpus = 1
    end
    node.vm.hostname = "test"
    node.vm.network :private_network, ip: TEST_IP
  end

  config.vm.define "k1m" do |node|
    node.vm.hostname = "k1m"
    node.vm.network :private_network, ip: K8S1_MASTER_IP
  end

  config.vm.define "k1n1" do |node|
    node.vm.hostname = "k1n1"
    node.vm.network :private_network, ip: K8S1_NODE_1_IP
  end

  config.vm.define "k1n2" do |node|
    node.vm.hostname = "k1n2"
    node.vm.network :private_network, ip: K8S1_NODE_2_IP
  end
end

我正准备拿来创建一个k8s集群。

启动后查看 vagrant 的密钥配置:

vagrant ssh-config

6. 插件功能

vagrant支持插件功能。这里介绍http代理的插件,毕竟研发k8s,代理也是必须的。

  1. 安装

    vagrant plugin install vagrant-proxyconf
    
  2. 配置

    配置这一块我用了宿主机的IP,使用127.0.0.1的话好像有问题。

      # プロキシ設定
      if Vagrant.has_plugin?("vagrant-proxyconf")
        config.proxy.http     = "http://192.168.1.103:8118"
        config.proxy.https    = "http://192.168.1.103:8118"
        config.proxy.no_proxy = "localhost,127.0.0.1,10.0.0.0/8"
      end
    

常见错误

  1. The executable ‘bsdtar’ Vagrant is trying to run was not found in the PATH variable.

    github上有 相关issue. 解决办法如下:

    apt install libarchive-tools
    
  2. dpkg: virtualbox-6.1: dependency problems, but configuring anyway as you requested

    由于依赖不满足,不让安装。强制安装再修复依赖即可。

    dpkg --force-depends -i virtualbox-6.1_6.1.18-142142_Debian_stretch_amd64.deb
    apt --fix-broken install -y
    

参考资料


Debian 9 配置 vue 开发环境

最近开始捡起来前端 vue 的开发,这里记录一下环境搭建的过程。

安装nodejs

官网教程 适用于大部分场景了。在这里我安装当前最新的LTS版 v14.x,两个命令即可:

curl -sL https://deb.nodesource.com/setup_14.x | bash -
apt-get install -y nodejs

很不幸,在我的机器上出现了下面的错误:

The AppStream system cache was updated, but some errors were detected, which might lead to missing metadata.

image-20201125122253041

实际上我也没有头绪。随意敲了几个命令,upgrade 了几个包解决了,具体原因还是不清楚:

apt-get update
apt-get upgrade
apt autoremove

image-20201125122823911

确认版本:

node -v
npm -v

image-20201125130514125

nodejs配置

使用阿里的镜像源

npm install -g cnpm --registry=https://registry.npm.taobao.org

在 .zshrc 或 .bashrc 中添加新命令

alias cnpm="npm --registry=https://registry.npm.taobao.org \
--cache=$HOME/.npm/.cache/cnpm \
--disturl=https://npm.taobao.org/dist \
--userconfig=$HOME/.cnpmrc"

安装vue-cli

npm install -g @vue/cli

查看版本:

vue --version

@vue/cli 4.5.9

很遗憾,在这里我也遇到了问题。

大概可以看出来系统已经安装过了vue,而且是 2.x 版本的vue。在这里先进行卸载。

npm ERR! EEXIST: file already exists, symlink '../lib/node_modules/@vue/cli/bin/vue.js' -> '/usr/bin/vue'

image-20201125132803736

卸载:

npm uninstall -g vue-cli

创建demo应用

由于目前vue已经到3的版本了,3也兼容2的版本。所以这里我就直接使用 vue3 做测试了。

vue create kelu

会弹出相关的交互式问题,下面是我做的选项,把 vuex router都安排上了。

image-20201125135011676

运行

npm run serve

从原有代码中运行

npm install
npm run serve

一个简单的 gin websocket 例子

这个例子是我在开发时候写的测试demo,框架基于 Gin。

基本功能非常简单:

  • 当客户端连接上的时候,发送一个自定义的id,

  • 当收到客户端的json信息时,基于不同的返回码,打印日志。

代码包含两个文件,一个是ws的通用文件ws.go,一个是逻辑处理文件kelu.go,在这里做个记录。

依赖包

github.com/gin-gonic/gin
github.com/gorilla/websocket

ws.go


package ws

import (
  "github.com/gorilla/websocket"
  "net/http"
  "github.com/gin-gonic/gin"
  "fmt"
  "github.com/kelu.org/base/pkg/app"
)

// WebSocket 更新用
var keluWsUpgrader = websocket.Upgrader{
  ReadBufferSize:  1024,
  WriteBufferSize: 1024,
  CheckOrigin:     checkOrigin,
}

func checkOrigin(r *http.Request) bool {
  return true
}

// 路由入口
func ApiWs(c *gin.Context) {
  ws, err := keluWsUpgrader.Upgrade(c.Writer, c.Request, nil)
  if err != nil {
    return
  }

  wsid, err := KeluWsOpen(ws)
  fmt.Println("kelu open socket: ",wsid)
  if err != nil {
    return
  }

  defer ws.Close()

  for {
    //读取ws中的数据
    receivedData := app.Response{}

    // メッセージ読み込み
    err = ws.ReadJSON(&receivedData)
    if err != nil {
      fmt.Printf("KeluWs reading ws error: %v", err)
      break
    }

    switch receivedData.Code {
    case http.StatusAccepted:
      // some code ... ...
      break;
    case http.StatusOK:
      // some code ... ...
      break;

    default:
      ws.WriteJSON(KeluWsBad(wsid,receivedData.Data))
    }

  }

  KeluWsDone(wsid)
  return
}

kelu.go

func KeluWsOpen(ws *websocket.Conn) (int64, error) {
  wsid := time.Now().UnixNano()
  welcome := app.Response{http.StatusAccepted, "ok", "ok", map[string]interface{}{"wsid": wsid}}
  err := ws.WriteJSON(welcome)
  if err != nil {
    fmt.Printf("open websocket error while writing message to client: %v", err)
    ws.Close()
    return 0, err
  }

  return wsid, nil
}

func KeluWsBad(wsid int64, data interface{}) *app.Response {
  resultData := app.Response{http.StatusBadRequest, strconv.FormatInt(wsid, 10), "", data}
  return &resultData
}

func KeluWsDone(wsid int64){
  // some code ... ...
}