Docker Verzeichnis mounten unter Windows 10

Um einen lokalen Ordner in einen Docker Container unter Windows 10 zu mounten, kann man entweder Docker für Windows verwenden oder wenn man die Windows 10 Home Edition verwendet, ist man gezwungen, dies per Hand mit Virtual Box erledigen.

Dazu muss man die Docker default Box auswählen in Virtual Box:

virtual_box_shared_folder

und einen neuen Gemeinsamen Ordner hinzufügen:virtual_box_shared_folder_add

Dann muss man die docker-machine neustarten in der Docker Toolbox, dadurch wird die docker default Virtual Box neugestartet:

docker-machine restart

Jetzt kann man sein Verzeichnis mounten in seiner docker-compose.yml:

volumes:
  - /htdocs/my_project:/var/www/html/

Jetzt wird der Ordner in dem Docker Container erfolgreich gemountet.

Mit dem folgenden Befehl kann getestet werden, ob das mounten erfolgreich war:

docker exec -it CONTAINER_ID ls -ll /var/www/html
Veröffentlicht unter Docker

Monolog Logging für AWS Cloudwatch Logs konfigurieren

Damit die Logs schön formatiert aus einer Symfony 4 Anwendung in AWS Cloudwatch ankommen, muss man Monolog folgendermaßen konfigurieren:

# config/services.yaml
Monolog\Formatter\JsonFormatter:
    calls:
        - [includeStacktraces]

und

# config/packages/prod/monolog.yaml
monolog:
  handlers:
    main:
      type:  stream
      level: error
      path:  '%kernel.logs_dir%/error.log'
      formatter: Monolog\Formatter\JsonFormatter

Danach muss man der Cloudwatch Daemon konfigurieren:

# /etc/awslogs/awslogs.conf
[general]
# Path to the CloudWatch Logs agent's state file. The agent uses this file to maintain
# client side state across its executions.
state_file = /var/lib/awslogs/agent-state

[/var/www/html/var/log/error.prod.log]
datetime_format = [%Y-%m-%d H:%M:%S]
file = /var/www/html/var/log/error.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = test_group_name/error_log

und man erhält wunderbare (aggregierte) ErrorLog Informationen in Cloudwatch Logs Insight:

 

 

11 AWS Cloudformation Experten Tricks

Bei meiner Arbeit mit Cloudfromation habe ich viel nützliche Tipps gesammelt, die ich gern teilen will.

1. Eine IDE mit Autocomplete verwenden

Für die Jetbrains IDEs wie PHPStorm, Webstorm oder IntelliJ gibt es ein sehr gutes AWS Cloudfromation Plugin namens AWS Cloudfromation von Leonid Shalupov:

AWS Cloudfromation Plugin von Leonid Shalupov

Dieses biete Autocomplete für die IDE an und eine automatische Formatüberprüfung, ob Attribute gesetzt werden, die dort nicht erlaubt sind. Auf diesem weg kann man viele Fehler schon vor dem validieren finden und spart viel Zeit.

AWS Cloudfromation Autocomple

2. AWS-CLI Befehle verwenden weiterlesen…

Cloudformation reboot einer EC2 Instanz

Damit eine Instanz neu neugestartet wird, nachdem die Einrichtung erfolgt ist, muss man folgende Befehl in die UserData Sektion eintragen im Cloudformation Template:

UserData:
  # is executed as root user
  Fn::Base64:
    !Sub |
      #!/bin/bash -xe
      yum update -y aws-cfn-bootstrap
      /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --configsets InstallAndRun --region ${AWS::Region}
      /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
      reboot

AWS Lanbda erstellen eines Route53 A Records Eintrages

Mit Hilfe der folgende Python AWS Lambda Funktion kann man einen A Record in Route53 erstellen/updaten:

import json
import boto3

route53 = boto3.client('route53')

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    domain = event['domain']

    route53.change_resource_record_sets(
        HostedZoneId='HostedZoneId',
        ChangeBatch={
            'Comment': 'Update or Insert an A Record',
            'Changes': [
                {
                    'Action': 'UPSERT',
                    'ResourceRecordSet': {
                        'Name': domain,
                        'Type': 'A',
                        'SetIdentifier': domain,
                        'Region': 'region',
                        'ResourceRecords': [
                            {
                                'Value': '1.1.1.1'
                            }
                        ],
                        'TTL': 300
                    }
                }
            ]
        }
    )

 

Dazu muss die Labda Funktion die notwendigen Rechte für Route53 besitzen.

Die Dokumentation ist hier.

Die Funktion kann getestet werden mit:

{
  "domain": "foo.bar.de"
}

AWS Cloudfromation Template YAML Zeilenumbruch

Um einen mehrzeiligen Text in Cloudformation Templates zu platzieren, gibt es eine elegante Lösung – der YAML >- Operator:

/var/www/html/public/index.php:
  content: >-
    <html>
      <body>
        <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
        <p/>
        <?php
          // Print out the current data and time
          print "The Current Date and Time is: <br/>";
          print date("g:i A l, F j Y.");
        ?>
        <?php  phpinfo(); ?>
      </body>
    </html>

Alternativ wird in vielen offiziellen Beispielen das sehr unhandliche Format mit der Join Funktion benutzt:

  /var/www/html/index.php:
    content: !Join
      - ''
      - - |
          <html>
        - |2
            <body>
        - |2
              <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
        - |2
              <p/>
        - |2
              <?php
        - |2
                // Print out the current data and time
        - |2
                print "The Current Date and Time is: <br/>";
        - |2
                print date("g:i A l, F j Y.");
        - |2
              ?>
        - |2
              <?php  phpinfo(); ?>
        - |2
            </body>
        - |
          </html>

 

AWS Opsworks ändert SSH Keys auf EC2 Instanzen

Ich hatte gerade das Problem, dass ich mich nicht mehr mit meinem SSH Key auf meine EC2 Instanz einloggen konnte:

Server refused our key

Ich habe herausgefunden, dass es daran lag, dass ich AWS Opsworks Stacks ausprobiert hatte und genau diesen Key angebeben hatte für den neuen Stack.

Meine Rettung war, dass man sich über die AWS Console auch auf die Instanzen mit SSH verbinden kann ohne das Zertifikat:

Was Opsworks dann getan hat, war die Key von den bestehenden Instanzen zu kopieren und dem root-User, nicht mehr meine ec2-user zuzuteilen.

Dies geschah aber leider auch nicht korrekt, sondern der Key in /root/.ssh/authorized_keys war geändert worden in ein falsches Format durch Opsworks:

command="echo 'Please login as the ec2-user user rather than root user.';echo;sleep 10" xxxxxxxxxxxxxxxxxxxMY SSH Keyxxxxxxxxxxxxxxxxxxx

Um das Login wieder herzustellen, habe ich den Text vor meinem SSH Key entfernt und kopiert nach /home/ec2-user/.ssh/.

Danach müssen noch die passenden Rechte gesetzt werden als ec2-user:

mkdir /home/ec2-user/.ssh
sudo chown -R ec2-user:ec2-user /home/ec2-user/.ssh
chmod 700 /home/ec2-user/.ssh
chmod 600 /home/ec2-user/.ssh/authorized_keys

Danach war das Login wieder möglich. Es sollte nicht vergessen werden, den root SSH Key zu entfernen.

AWS Zeitzone richtig einstellen Amazon Linux 2 und RDS MySQL PHP

Damit in den Logs und in der Datenbank die korrekten Zeitstempel der eigenen Zeitzone verwendet werden, muss man

1. Die Systemzeit der EC2 Instanz konfigurieren

sudo ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime

und in der Datei /etc/sysconfig/clock die Zeitzone eintragen:

sudo vi /etc/sysconfig/clock
ZONE="Europe/Berlin"

Danach muss ein Reboot der Instanz erfolgen:

sudo reboot

Die Anpassung kann überprüft werden mit

date

Quelle weiterlesen…

letsencrypt AWS http challenge

Ich hatte das Problem, dass beim Erneuern des Letsencrypt Zertifikates per Cronjob unter Amazon Linux 2

certbot renew --post-hook "systemctl reload httpd"  >> /var/log/certbot.log 2>&1

das SSL Zertifikat nicht erneuert wurde, sondern folgende Fehlermeldung auftrat:

Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',)
Attempting to renew cert (foo.de) from /etc/letsencrypt/renewal/foo.conf produced an unexpected error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',). Skipping.

Ich habe dann in Konfiguration geschaut: /etc/letsencrypt/renewal/foo.conf und dort den Authentificator geändert auf apache und den Authentificator Challenge auf HTTP (über den Webserver).

# Options used in the renewal process
[renewalparams]
account = xxx
server = https://acme-v02.api.letsencrypt.org/directory
authenticator = apache
installer = apache
pref_challs = http-01,

Danach war wichtig noch den Port 80 in der Security Group freizuschalten für die Authentifizierung und nach erneuter Eingabe des Befehls

certbot renew

wurde das Zertifikat wurde erfolgreich erneuert.

Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for foo.de
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/foo.de/fullchain.pem