• ingress-nginx controller not work for fanout configuration

    Firstly, I want to says: Reading CHANGE_LOG will help you reduce the pain.

    ingress-nginx has breaking changes from NGINX 0.22.0

    Annotation nginx.ingress.kubernetes.io/rewrite-target has changed and will not behave as expected if you don't update them.
    
    Refer to https://kubernetes.github.io/ingress-nginx/examples/rewrite/#rewrite-target on how to change it.
    
    Refer to [#3174 (comment)](https://github.com/kubernetes/ingress-nginx/pull/3174#issuecomment-455665710) on how to do seamless migration.
    

    From the documentation page at https://kubernetes.io/docs/concepts/services-networking/ingress/, you can define a fanout configuration routes traffic from a single IP address to more than one service, based on the HTTP URI being requested. An Ingress allows you to keep the number of loadbalancers down to a minimum.

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: simple-fanout-example
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      rules:
      - host: foo.bar.com
        http:
          paths:
          - path: /foo
            backend:
              serviceName: service1
              servicePort: 4200
          - path: /bar
            backend:
              serviceName: service2
              servicePort: 8080
    

    However, it’s not work as expected if you have updated to the version 0.22.0 or newer. You need to change these annotations:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: simple-fanout-example
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$1
    spec:
      rules:
      - host: foo.bar.com
        http:
          paths:
          - path: /foo/?(.*)
            backend:
              serviceName: service1
              servicePort: 4200
          - path: /bar/?(.*)
            backend:
              serviceName: service2
              servicePort: 8080
    

    Enjoy your time!

  • Running a Docker container as non-root user

    By default, Docker container will be run as root user, this can cause us pain. We could tell Docker to run as an ordinary user instead of root.

    We could build a Dockerfile like this:

    FROM node:latest
    
    # Add user so we dont run app as root
    RUN groupadd -r node && useradd -r -g node node \
        && mkdir -p /home/node/<your-app-name> \
        && chown -R node:node /home/node
    
    WORKDIR /home/node/<your-app-name>
    
    COPY . .
    RUN npm install
    
    USER node
    EXPOSE 3000
    
    CMD ["npm", "start"]
    

    Happy building ~v~

  • Disable firewall in EC2 instance from AWS Console

    I have locked myself out of SSH with UFW in EC2 AWS. Then, I can’t reconnect.

    I found this script and it works with below steps:

    • Stop your problem instance
    • Paste this script in Instance Settings > View/Change User Data
    Content-Type: multipart/mixed; boundary="//"
    MIME-Version: 1.0
    --//
    Content-Type: text/cloud-config; charset="us-ascii"
    MIME-Version: 1.0
    Content-Transfer-Encoding: 7bit
    Content-Disposition: attachment; filename="cloud-config.txt"
    #cloud-config
    cloud_final_modules:
    - [scripts-user, always]
    --//
    Content-Type: text/x-shellscript; charset="us-ascii"
    MIME-Version: 1.0
    Content-Transfer-Encoding: 7bit
    Content-Disposition: attachment; filename="userdata.txt"
    #!/bin/bash
    ufw disable
    iptables -L
    iptables -F
    --//
    
    • Start your instance and now you should be able to SSH
  • Host ASP.NET Core on Linux with Nginx

    This is a helper document guide how to setup, config and deploy an .NET Core Web Engine Hosting on an Ubuntu Server.

    Access to Linux server

    Run below command and input password

    You can copy your local ssh key to server and no need password to login next time

    ssh-copy-id -i .ssh/id_rsa [email protected]/ip
    

    Install Nginx

    sudo apt-get update
    sudo apt-get install nginx
    

    Since Nginx was installed for the first time, explicitly start it by running:

    sudo systemctl start nginx
    

    Config Nginx

    To config Nginx as a reserve proxy to forward request to ASP.NET Core app, modify /etc/nginx/sites-available/default and replace or create a new sites-available

    cd /etc/nginx/sites-available
    touch site_name
    sudo nano site_name
    

    with the following contents

    upstream site_name_svc  {
        server 127.0.0.1:5432;
    }
    
    server {
        server_name your_site_link;
        listen 80;
    
        root /usr/share/nginx/html;
        index index.html index.htm;
    
        location / {
            proxy_pass http://site_name_svc;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    

    This Nginx config file forwards incoming public traffic from port 80 to port 5432

    Link your site to sites-enabled, then you can easy switch off site by remove syslink here and re-use again without re-config

    sudo ln -s /etc/nginx/sites-available/kkday-test /etc/nginx/sites-enabled
    

    Verify your config files

    sudo nginx -t
    

    If successful, reload Nginx to pickup the changes

    sudo service nginx reload
    

    Monitoring application

    Use systemd and create a service file to start and monitor the underlying web app. systemd is an init system that provides many powerful features for starting, stopping, and managing processes.

    Create service file

    sudo nano /etc/systemd/system/service_name.service
    
    [Unit]
    Description=Example .NET Web API Application running on Ubuntu
    
    [Service]
    WorkingDirectory=/path-to-your-app
    ExecStart=/usr/bin/dotnet /path-to-your-app/working-file.dll
    Restart=always
    RestartSec=10  # Restart service after 10 seconds if dotnet service crashes
    SyslogIdentifier=dotnet-example
    User=www-data
    Environment=ASPNETCORE_ENVIRONMENT=Production
    Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
    
    [Install]
    WantedBy=multi-user.target
    

    Note: If the user www-data isn’t used by the configuration, the user defined here must be created first and given proper ownership for files.

    Save the file and enable the service.

    systemctl enable service_name.service
    

    Start the service and verify that it’s running.

    systemctl start service_name.service
    systemctl status service_name.service
    

    Now you can access your app from a browser on local machine via http://localhost

  • Minimal Docker container

    With Docker multi stage, you can use multiple base image (call as builder) to build necessary files, assets and copy stuff over to final image after.

    Here is some tricks:

    • You can use node:alpine, bitnami-docker-node or other smaller images if it’s enough to build your app.
    • Copy necessary files only
    • Base node docker image included yarn, it’s better some time (ex: build node-sass)

    Example:

    # node builder
    FROM node:8.9.3 as nodebuilder
    RUN mkdir publish
    COPY gulpfile.js webpack.config.js package.json publish/
    COPY ./Vue publish/Vue
    COPY ./wwwroot publish/wwwroot
    WORKDIR /publish
    
    RUN cd /publish && yarn install \
        && yarn gulp all \
        && yarn run build
    
    # dotnet builder
    FROM microsoft/dotnet:2.0.0-sdk as builder
    RUN mkdir publish
    COPY . publish
    WORKDIR publish
    RUN dotnet restore <app_name>.csproj
    RUN dotnet publish <app_name>.csproj --configuration Release --output ./out
    
    # final image
    FROM microsoft/dotnet:2.0.0-runtime
    WORKDIR /dotnetapp
    COPY --from=builder publish/out .
    COPY --from=nodebuilder publish/wwwroot ./wwwroot
    ENTRYPOINT ["dotnet", "<app_name>.dll"]