nixops-aws icon indicating copy to clipboard operation
nixops-aws copied to clipboard

Manual ec2 example fails

Open tbenst opened this issue 5 years ago • 1 comments

I copied the files from https://nixos.org/nixops/manual/#sec-deploying-to-ec2, and only changed the accessKeyId. Unfortunately I get this error:

> nixops create ./load-balancer.nix ./load-balancer-ec2.nix -d load-balancer-ec2
created deployment ‘7d8239f3-0d5b-11ea-89e6-02428c63fe0c’
7d8239f3-0d5b-11ea-89e6-02428c63fe0c
> nixops deploy -d load-balancer-ec2
error: I don't know an AMI for virtualisation type pv-ebs with instance type m1.small
(use '--show-trace' to show detailed location information)
error: evaluation of the deployment specification failed

Next I tried switching to region = "us-west-2" and deployment.ec2.instanceType = "t2.micro";. Now I get the same error for each instance:

error: Multiple exceptions (3): 
  * backend1: EC2ResponseError: 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<Response><Errors><Error><Code>VPCResourceNotSpecified</Code><Message>The specified instance type can only be used in a VPC. A subnet ID or network interface ID is required to carry out the request.</Message></Error></Errors><RequestID>8f4346fb-3a7e-4263-b0d1-17acd0a0d446</RequestID></Response>

Anyone know what tweaks need to be made so the manual example works? Thanks!

Edit: after some googling, it appears this may be because newer AWS accounts have a default VPC but older ones do not. https://github.com/hashicorp/terraform/issues/4367. That said, it would be nice if the example was "more" declarative

Edit2: I just made a new AWS account and this did not resolve the issue. Appears the basic example needs to show configuring a VPC

tbenst avatar Nov 22 '19 19:11 tbenst

For anyone that gets stuck, here's a configuration for AWS now that VPC must be specified. Hope it saves someone a few hours :). Would be great to update the manual with a working example. I based this off of https://github.com/nh2/nixops-tutorial and https://github.com/NixOS/nixops-aws/blob/master/examples/vpc.nix.

nginx-server-ec2.nix:

let
  region = "us-west-2";
  accessKeyId = "my-access-key"; # symbolic name looked up in ~/.ec2-keys or a ~/.aws/credentials profile name
  # We must declare an AWS Subnet for each Availability Zone
  # because Subnets cannot span AZs.
  subnets = [
    { name = "nixops-vpc-subnet-a"; cidr = "10.0.0.0/19"; zone = "${region}a"; }
    { name = "nixops-vpc-subnet-b"; cidr = "10.0.32.0/19"; zone = "${region}b"; }
    { name = "nixops-vpc-subnet-c"; cidr = "10.0.64.0/19"; zone = "${region}c"; }
    { name = "nixops-vpc-subnet-d"; cidr = "10.0.96.0/19"; zone = "${region}d"; }
  ];
  domain = "example.com";
  ec2 = { resources, ... }: {
    deployment.targetEnv = "ec2";
    deployment.ec2.accessKeyId = accessKeyId;
    deployment.ec2.region = region;
    deployment.ec2.subnetId = resources.vpcSubnets.nixops-vpc-subnet-c;
    deployment.ec2.instanceType = "t2.micro";
    deployment.ec2.keyPair = resources.ec2KeyPairs.my-key-pair;
    deployment.ec2.associatePublicIpAddress = true;
    deployment.ec2.elasticIPv4 = resources.elasticIPs.eip;
    deployment.ec2.ebsBoot = true;
    deployment.ec2.ebsInitialRootDiskSize = 20;
    deployment.ec2.securityGroupIds = [ "allow-ssh" "allow-http" ];
  };
  lib = (import <nixpkgs> {}).lib;
in
{
  nginx-server = ec2;

  resources = {
    # Provision an EC2 key pair.
    ec2KeyPairs.my-key-pair =
      { inherit region accessKeyId; };

    # create security groups
    ec2SecurityGroups.allow-ssh = { resources, ... }: {
      inherit region accessKeyId;
      name = "allow-ssh";
      description = "allow-ssh";
      vpcId = resources.vpc.nixops-vpc;
      rules = [
        { fromPort = 22; toPort = 22; sourceIp = "0.0.0.0/0"; }
      ];
    };

    ec2SecurityGroups.allow-http = { resources, ... }: {
      inherit region accessKeyId;
      name = "allow-http";
      description = "allow-http";
      vpcId = resources.vpc.nixops-vpc;
      rules = [
        { fromPort = 80; toPort = 80; sourceIp = "0.0.0.0/0"; }
        { fromPort = 443; toPort = 443; sourceIp = "0.0.0.0/0"; }
      ];
    };

    # configure VPC
    vpc.nixops-vpc = {
      inherit region accessKeyId;
      instanceTenancy = "default";
      enableDnsSupport = true;
      enableDnsHostnames = true;
      cidrBlock = "10.0.0.0/16";
      tags.Source = "NixOps";
    };

    vpcSubnets =
      let
        makeSubnet = {cidr, zone}:
          { resources, ... }: {
            inherit region zone accessKeyId;
            vpcId = resources.vpc.nixops-vpc;
            cidrBlock = cidr;
            mapPublicIpOnLaunch = true;
            tags.Source = "NixOps";
        };
      in
        builtins.listToAttrs
          (map
            ({ name, cidr, zone }: lib.nameValuePair name (makeSubnet { inherit cidr zone; }) )
            subnets
          );

    vpcRouteTables = {
      route-table = { resources, ... }: {
        inherit accessKeyId region;
        vpcId = resources.vpc.nixops-vpc;
      };
    };

    vpcRoutes = {
      igw-route = { resources, ... }: {
        inherit region accessKeyId;
        routeTableId = resources.vpcRouteTables.route-table;
        destinationCidrBlock = "0.0.0.0/0";
        gatewayId = resources.vpcInternetGateways.nixops-igw;
      };
    };

    vpcRouteTableAssociations =
      let
        association = subnetName: { resources, ... }: {
          inherit accessKeyId region;
          subnetId = resources.vpcSubnets."${subnetName}";
          routeTableId = resources.vpcRouteTables.route-table;
        };
      in
        builtins.listToAttrs
          (map
            ({ name, ... }: lib.nameValuePair "association-${name}" (association name) )
            subnets
          );
    vpcInternetGateways.nixops-igw = { resources, ... }: {
      inherit accessKeyId region;
      vpcId = resources.vpc.nixops-vpc;
    };

    # Optional: static IP address
    elasticIPs.eip = {
      inherit region accessKeyId;
      vpc = true;
    };
  };
}

nginx-server.nix:

{
  # special NixOps config
  network = {
    description = "Nginx server";
    enableRollback = true;
  };
  # end special NixOps config

  # from https://gist.github.com/nh2/28bce850755cf14bd7749ea78e4238ab
  /* boot.kernelModules = [ "tcp_bbr" ]; # faster tcp kernel support
  # Enable BBR congestion control
  boot.kernel.sysctl."net.ipv4.tcp_congestion_control" = "bbr"; */

  nginx-server = { config, pkgs, ... }: {
    networking.firewall.enable = true;
      # Reject instead of drop.
      networking.firewall.rejectPackets = true;
      networking.firewall.allowedTCPPorts = [
        22
        80 # nginx
        443 # nginx
      ];

    services.nginx = {
      enable = true;
      /* virtualHosts."${domain}" = {
        enableACME = true;
      }; */
    };
  };
}

Then:

> nixops create ./nginx-server.nix ./nginx-server-ec2.nix -d nginx-server-ec2
> nixops deploy -d nginx-server-ec2

tbenst avatar Nov 24 '19 20:11 tbenst