Deploying a VM with Wireguard and Gateway
Introduction
We present here the relevant information when it comes to deploying a virtual machine with Wireguard and a gateway.
Client Configurations
To configure the client, have a look at this section.
Code Example
import { FilterOptions, GatewayNameModel, GridClient, MachineModel, MachinesModel, NetworkModel } from "../src";
import { config, getClient } from "./client_loader";
import { log } from "./utils";
function createNetworkModel(gwNode: number, name: string): NetworkModel {
return {
name,
addAccess: true,
accessNodeId: gwNode,
ip_range: "10.238.0.0/16",
} as NetworkModel;
}
function createMachineModel(node: number) {
return {
name: "testvm1",
node_id: node,
public_ip: false,
planetary: true,
cpu: 1,
memory: 1024 * 2,
rootfs_size: 0,
disks: [],
flist: "https://hub.grid.tf/tf-official-apps/threefoldtech-ubuntu-22.04.flist",
entrypoint: "/usr/bin/python3 -m http.server --bind ::",
env: {
SSH_KEY: config.ssh_key,
},
} as MachineModel;
}
function createMachinesModel(vm: MachineModel, network: NetworkModel): MachinesModel {
return {
name: "newVMs",
network,
machines: [vm],
metadata: "",
description: "test deploying VMs with wireguard via ts grid3 client",
} as MachinesModel;
}
function createGwModel(node_id: number, ip: string, networkName: string, name: string, port: number) {
return {
name,
node_id,
tls_passthrough: false,
backends: [`http://${ip}:${port}`],
network: networkName,
} as GatewayNameModel;
}
async function main() {
const grid3 = await getClient();
const gwNode = +(await grid3.capacity.filterNodes({ gateway: true }))[0].nodeId;
const vmQueryOptions: FilterOptions = {
cru: 1,
mru: 2, // GB
availableFor: grid3.twinId,
farmId: 1,
};
const vmNode = +(await grid3.capacity.filterNodes(vmQueryOptions))[0].nodeId;
const network = createNetworkModel(gwNode, "monNetwork");
const vm = createMachineModel(vmNode);
const machines = createMachinesModel(vm, network);
log(`Deploying vm on node: ${vmNode}, with network node: ${gwNode}`);
// deploy the vm
const vmResult = await grid3.machines.deploy(machines);
log(vmResult);
const deployedVm = await grid3.machines.getObj(machines.name);
log("+++ deployed vm +++");
log(deployedVm);
// deploy the gateway
const vmPrivateIP = (deployedVm as { interfaces: { ip: string }[] }[])[0].interfaces[0].ip;
const gateway = createGwModel(gwNode, vmPrivateIP, network.name, "pyserver", 8000);
log(`deploying gateway ${network.name} on node ${gwNode}`);
const gatewayResult = await grid3.gateway.deploy_name(gateway);
log(gatewayResult);
log("+++ Deployed gateway +++");
const deployedGw = await grid3.gateway.getObj(gateway.name);
log(deployedGw);
await grid3.disconnect();
}
main();
Detailed Explanation
What we need to do with that code is: Deploy a name gateway with the wireguard IP as the backend; that allows accessing a server inside the vm through the gateway using the private network (wireguard) as the backend.
This will be done through the following steps:
Get the Client
const grid3 = getClient();
Get the Nodes
Determine the deploying nodes for the vm, network and gateway.
-
Gateway and network access node
const gwNode = +(await grid3.capacity.filterNodes({ gateway: true }))[0].nodeId;
Using the
filterNodes
method, will get the first gateway node id, we will deploy the gateway and will use it as our network access node.The gateway node must be the same as the network access node.
-
VM node
we need to set the filter options first for this example we will deploy the vm with 1 cpu, 2 GB of memory. now will crete a
FilterOptions
object with that specs and get the firs node id of the result.const vmQueryOptions: FilterOptions = { cru: 1, mru: 2, // GB availableFor: grid3.twinId, farmId: 1, }; const vmNode = +(await grid3.capacity.filterNodes(vmQueryOptions))[0].nodeId;
Deploy the VM
We need to create the network and machine models, the deploy the VM
const network = createNetworkModel(gwNode, "monNetwork");
const vm = createMachineModel(vmNode);
const machines = createMachinesModel(vm, network);
log(`Deploying vm on node: ${vmNode}, with network node: ${gwNode}`);
// deploy the vm
const vmResult = await grid3.machines.deploy(machines);
log(vmResult);
-
CreateNetWorkModel
: we are creating a network and set the node id to begwNode
, the namemonNetwork
and inside the function we setaddAccess: true
to add wireguard access. -
createMachineModel
andcreateMachinesModel
is similar to the previous section of deploying a single VM, but we are passing the createdNetworkModel
to the machines model and the entry point here runs a simple python server.
Deploy the Gateway
Now we have our VM deployed with it's network, we need to make the gateway on the same node, same network and pointing to the VM's private IP address.
-
Get the VM's private IP address:
const vmPrivateIP = (deployedVm as { interfaces: { ip: string }[] }[])[0].interfaces[0].ip;
-
Create the Gateway name model:
const gateway = createGwModel(gwNode, vmPrivateIP, network.name, "pyserver", 8000);
This will create a
GatewayNameModel
with the following properties:name
: the subdomain namenode_id
: the gateway node idtls_passthrough: false
backends: [
http://${ip}:${port}]
: the private ip address and the port number of our machinenetwork: networkName
: the network name, we already created earlier.
Get the Deployments Information
const deployedVm = await grid3.machines.getObj(machines.name);
log("+++ deployed vm +++");
log(deployedVm);
log("+++ Deployed gateway +++");
const deployedGw = await grid3.gateway.getObj(gateway.name);
log(deployedGw);
-
deployedVm
: is an array of one object contains the details about the vm deployment.[ { version: 0, contractId: 30658, nodeId: 11, name: 'testvm1', created: 1686225126, status: 'ok', message: '', flist: 'https://hub.grid.tf/tf-official-apps/threefoldtech-ubuntu-22.04.flist', publicIP: null, planetary: '302:9e63:7d43:b742:3582:a831:cd41:3f19', interfaces: [ { network: 'monNetwork', ip: '10.238.2.2' } ], capacity: { cpu: 1, memory: 2048 }, mounts: [], env: { SSH_KEY: 'ssh' }, entrypoint: '/usr/bin/python3 -m http.server --bind ::', metadata: '{"type":"vm","name":"newVMs","projectName":""}', description: 'test deploying VMs with wireguard via ts grid3 client', rootfs_size: 0, corex: false } ]
-
deployedGw
: is an array of one object contains the details of the gateway name.[ { version: 0, contractId: 30659, name: 'pyserver1', created: 1686225139, status: 'ok', message: '', type: 'gateway-name-proxy', domain: 'pyserver1.gent02.dev.grid.tf', tls_passthrough: false, backends: [ 'http://10.238.2.2:8000' ], metadata: '{"type":"gateway","name":"pyserver1","projectName":""}', description: '' } ]
Now we can access the vm using the
domain
that returned in the object.
Disconnect the Client
finally we need to disconnect the client using await grid3.disconnect();
Delete the Deployments
If we want to delete the deployments we can just do this:
const deletedMachines = await grid3.machines.delete({ name: machines.name});
log(deletedMachines);
const deletedGW = await grid3.gateway.delete_name({ name: gateway.name});
log(deletedGW);
Conclusion
This section presented a detailed description on how to create a virtual machine with private IP using Wireguard and use it as a backend for a name gateway.
If you have any questions, you can ask the ThreeFold community for help on the ThreeFold Forum or on the ThreeFold Grid Tester Community on Telegram.