Category Archives: Allgemein

Grafana behind Nginx Reverse Proxy…

The subdomain server.rocworks.at is redirected by my provider to my IP at home where Nginx (with Letsencrypt Certificate) is running and it forwards /grafana to my Grafana Docker Instance. Access to Grafana is possible via https://server.rocworks.at/grafana.

Nginx Configuration (sites-enabled/default)

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name server.rocworks.at;

        location / {
                try_files $uri $uri/ =404;
        }

        location /grafana/ {
            proxy_pass http://docker1:3000/;
        }
}

Grafana Configuration (/etc/grafana/grafana.ini)

[server]
# Protocol (http or https)
protocol = http

# The http port to use
http_port = 3000

# The public facing domain name used to access grafana from a browser
domain = server.rocworks.at

# Root Url (NOTE: there is not Port in the URL)
root_url = %(protocol)s://%(domain)s/grafana

enforce_domain = false

Backup and Restore PostgreSQL Container Database …

Backup a Database

[root@avcentos ~]# cat pgbackup.sh
cn=postgres # set container name
db=${1:-mydb}
docker exec -t $cn pg_dump -c -U postgres $db > dump_`date +%d-%m-%Y"-"%H%M`.sql

Restore a Database

[root@avcentos ~]# cat pgrestore.sh
if [ ! -f "$1" ]
then
  echo File does not exist.
else
  cn=postgres # set container name
  db=${2:-mydb}
  echo Restore to $db...
  cat $1 | docker exec -i $cn psql -U postgres -d $db
fi

Drop a Database

# First kill connected sessions
SELECT pg_terminate_backend(pg_stat_activity.pid)
 FROM pg_stat_activity
 WHERE pg_stat_activity.datname = 'mydb';

# Drop your database
DROP DATABASE mydb;

Kibana and PgAdmin4 with NGINX Reverse Proxy on Docker…

If you have multiple services running on Docker with different ports, you have to open ports in your firewall and you have to access the services via different ports in the browser. To have one access port (port 80 or 443) you can use a reverse proxy.

In our case we used NGINX to redirect the access to Kibana (Elasticsearch Dashboard Tool) and PgAdmin4 (PostgreSQL Admin Tool) so that we can access both services on the same port (80) in the browser with different base paths: http://localhost/kibana and http://localhost/pgadmin.

docker-compose.yml:

version: '3.0'
services:
  elasticsearch:
    hostname: elasticsearch
    image: elasticsearch:7.5.0
    ports:
      - 9200:9200
      - 9300:9300
    volumes:
      - esdata:/usr/share/elasticsearch/data
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  

  kibana: 
    hostname: kibana
    image: kibana:7.5.0
    depends_on:
      - elasticsearch        
    environment:
      - XPACK_MONITORING_ENABLED=false
      - LOGGING_QUIET=true
      - SERVER_BASEPATH=/kibana
      - SERVER_REWRITEBASEPATH=true    

  postgres:
    hostname: postgres
    image: postgres:12.1
    ports:
      - 5432:5432
    volumes:
      - postgresdb:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=manager

  pgadmin: 
    hostname: pgadmin
    image: dpage/pgadmin4
    volumes:
      - pgadmin:/var/lib/pgadmin
    environment:
      - PGADMIN_DEFAULT_EMAIL=postgres
      - PGADMIN_DEFAULT_PASSWORD=manager
      - GUNICORN_ACCESS_LOGFILE=/dev/null

  proxy:
    hostname: proxy
    image: nginx:1.17.8
    ports:
      - 80:80
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - kibana 
      - pgadmin  

volumes:  
  esdata:
  postgresdb:
  pgadmin:

nginx.conf


user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /dev/null;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    server {
        listen 80;

        root /var/www;
        index index.html;

        location / {
            try_files $uri $uri/ =404;
        }
        
        location /pgadmin {
            proxy_pass http://pgadmin/;
            proxy_http_version 1.1;
            proxy_set_header X-Script-Name /pgadmin;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        location /kibana {
            proxy_pass http://kibana:5601/kibana;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }                    
    }
}

Store Docker Logs in Elasticsearch with Filebeat…

Create a filebeat configuation file named “filebeat.yaml”

filebeat.config:
  modules:
    path: ${path.config}/modules.d/*.yml
    reload.enabled: false

filebeat.autodiscover:
  providers:
    - type: docker
      hints.enabled: true

processors:
- add_cloud_metadata: ~

setup.ilm:
  enabled: false

output.elasticsearch:
  hosts: '${ELASTICSEARCH_HOSTS:elasticsearch:9200}'
  username: '${ELASTICSEARCH_USERNAME:}'
  password: '${ELASTICSEARCH_PASSWORD:}'

Create a docker-compose.yaml file

version: '3.0'
services:
  elasticsearch:
    hostname: elasticsearch
    image: elasticsearch:7.5.0
    ports:
      - 9200:9200
      - 9300:9300
    volumes:
      - esdata:/usr/share/elasticsearch/data
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
  kibana: 
    hostname: kibana
    image: kibana:7.5.0
    ports: 
      - 5601:5601
    depends_on:
      - elasticsearch        
    environment:
      - XPACK_MONITORING_ENABLED=false
      - LOGGING_QUIET=true
  filebeat:
    user: root
    hostname: filebeat
    image: docker.elastic.co/beats/filebeat:7.5.1
    command: filebeat -e -strict.perms=false
    volumes:
      - ./filebeat.yaml:/usr/share/filebeat/filebeat.yml
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - output.elasticsearch.hosts=["elasticsearch:9200"]
    depends_on:
      - elasticsearch
volumes: 
  esdata:

Startup the docker containers

docker-compuse up -d

Then you can access the logs via Kibana in the browser: http://localhost:5601/

Native Image with GraalVM

  1. Get the Windows version of GraalVM: https://github.com/oracle/graal/releases
  2. Extract it to C:\app
  3. Uninstall any Visual C++ 2010 Redistributables
  4. Get the Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO): https://www.microsoft.com/en-us/download/details.aspx?id=8442
    Use the GRMSDKX_EN_DVD.iso
  5. Mount the image and runF:\Setup\SDKSetup.exe 
  6. Run the Windows SDK 7.1 Command Prompt by going to Start > Microsoft Windows SDK v7.1 > Windows SDK 7.1 Command Prompt

c:\app\graalvm-ce-19.2.1\bin\native-image -jar Example.jar ^
--no-fallback ^
--report-unsupported-elements-at-runtime ^
--allow-incomplete-classpath ^

Clojure connected to WinCC OA…

Because Clojure is a JVM language, oa4j can be used to connect to WinCC Open Architecture.

(def manager (new JManager))

(defn callback [values]
  (let [v (reduce #(+ %1 %2) (map #(.getValueObject %) values))];
    (dpSet :ExampleDP_Trend1. v)))

(defn -main [& args]
  (.init manager (into-array args))
  (.start manager)
  (dpSet {:ExampleDP_Arg1. 2.0 :ExampleDP_Arg2. 3.0})
  (println (clojure.string/join "," 
    (dpGet [:ExampleDP_Arg1. :ExampleDP_Arg2.])))
  (let [c (dpConnect [:ExampleDP_Arg1. :ExampleDP_Arg2.] callback)]
    (Thread/sleep 180000)
    (.disconnect c))
  (.stop manager))

Full example can be found here.

Matrix Multiplication in Clojure…

Clojure code for matrix multiplication (source: Rosetta Code) … short & smart…

(def mmul (fn [a b]
  (let [nested-for (fn [f x y] (map (fn [a] (map (fn [b] (f a b)) y)) x))
        transpose (fn [m] (apply map vector m))]
    (nested-for (fn [x y] (reduce + (map * x y))) a (transpose b)))))

(def ma [[1 2 3 4]
         [4 3 2 1]])

(def mb [[1]
         [2]
         [3]
         [4]])

(defn -main [& args]
  (println (mmul ma mb)))

Siemens IoT2000 and WinCC OA….

Got an IoT2040 from Siemens. It is Arduino compatible and runs on Yocto Linux. ETM managed to compile the SCADA System WinCC Open Architecture on it, additionally we used a MQTT server (mosquitto), Node-Red with MQTT, and a MQTT Driver for WinCC OA written in Java… runs well. Just connected a simple LED and a Button with Node-Red, those can now be controlled by WinCC OA. Because WinCC OA runs on it, it can be used to connect a wide range of different devices (a lot of drivers are available for WinCC OA).

Perfect as an Edge device to collect data from the field… Industrial IoT with Siemens!