Friday, 22 March 2019

Creating a minimal Docker image for Go application

Let's create a minimal Docker image which contains an arbitrary Go application. As an example application, we can use "Hello world":

cmd/main.go:

package main
import (
   "fmt"
)
func main() {
   fmt.Println("Hello, world!")
}

To build it and place the executable in bin directory we need to run go build:

$ go build -o bin/hello-world cmd/main.go

To test the executable, let's run it:

$ ./bin/hello-world 
Hello, world!

We want to create a Docker image which, when started, runs this binary. We first have to add Dockerfile - a file which defines how will Docker image be created. Creating a Docker image is like creating a lasagne: we take a base layer and then keep adding new layers on top of each other. Dockerfile specifies what will be the base Docker image (base layer), which application has to reside in it, what is its environment and dependencies that have to be installed and also how will that app be executed (or, what shall be executed when that image is launched).

In our case, we only want to have a single binary in the container and we want it to be launched. For this use case, our Dockerfile can be like this:

go-docker-hello-world/Dockerfile:

FROM scratch
COPY bin/hello-world app/
CMD ["/app/hello-world"]


FROM scratch specifies that empty image (0 bytes!) shall be used as a base layer (or...we can say that there is no base layer).

COPY copies files or directories from source in the host to destination in the container. Working directory on host can be specified via context argument to docker build command. Current directory is used by default and in our case that's go-docker-hello-world. Our binary will be copied here from bin directory on host into the app directory in the container. If destination has to be directory, a slash (/) hast to be added after the destination name. If we didn't add slash, COPY would have copied our binary into the root directory of the container and would have renamed it to app.

CMD contains the name of the executable that has to be run upon container's launch. We need to use an array format (square brackets) as Docker then uses the first argument as the entry point (process that is executed first) and subsequent elements are its arguments. If we used "/app/hello-world" instead of ["/app/hello-world"] Docker would have tried to pass the name of the executable as an argument to /bin/sh but as base image is empty, shell is not present and we'd get an error when running the container:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown.
Let's create the container:

go-docker-hello-world$ docker build -t helloworld ./
Sending build context to Docker daemon 2.055MB
Step 1/3 : FROM scratch
--->
Step 2/3 : COPY bin/hello-world app/
---> 7c0c34e6ad64
Step 3/3 : CMD ["/app/hello-world"]
---> Running in b3f5695b79c5
Removing intermediate container b3f5695b79c5
---> 171dbd862be1
Successfully built 171dbd862be1
Successfully tagged helloworld:latest


-t applies a tag (name) to the container which can be used later in container managing commands (it is easier to use some descriptive name rather than container ID which is just an array of numbers).

./ specifies the context (the current working directory) for commands in the Dockerfile.

Let's verify that it appears in the list of images:

$ docker images
REPOSITORY   TAG    IMAGE ID       CREATED       SIZE
helloworld latest 171dbd862be1  42 minutes ago   2MB


Let's inspect it to verify that entry point is indeed our application:

$ docker inspect 171dbd862be1
[
    {
        "Id": "sha256:171dbd862be107306bcad870587f8961c00566b946a4d2717ccbf3863492ca2c",
        "RepoTags": [
            "helloworld:latest"
        ],
        "RepoDigests": [],
        "Parent": "sha256:7c0c34e6ad64538ff493910efd6046043b6fa28e78015be6333fcd2e880122d4",
        "Comment": "",
        "Created": "2019-03-22T16:15:30.7049579Z",
        "Container": "b3f5695b79c5add5e86af2ea02b893bd5ed35381221cca1fbf84dd6ea401b69e",
        "ContainerConfig": {
            "Hostname": "b3f5695b79c5",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/app/hello-world\"]"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:7c0c34e6ad64538ff493910efd6046043b6fa28e78015be6333fcd2e880122d4",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "18.09.3",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/app/hello-world"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:7c0c34e6ad64538ff493910efd6046043b6fa28e78015be6333fcd2e880122d4",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 1997502,
        "VirtualSize": 1997502,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/86d02e448ac1c650f65d6eb30b21eeea2f13f176918ccd6af3440c0d89336b19/merged",
                "UpperDir": "/var/lib/docker/overlay2/86d02e448ac1c650f65d6eb30b21eeea2f13f176918ccd6af3440c0d89336b19/diff",
                "WorkDir": "/var/lib/docker/overlay2/86d02e448ac1c650f65d6eb30b21eeea2f13f176918ccd6af3440c0d89336b19/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:60fdb797c60194a24fa8135f6a1dbe2ed03172037ff5e63eedfc372c2a92964d"
            ]
        },
        "Metadata": {
            "LastTagTime": "2019-03-22T16:15:30.835954727Z"
        }
    }
]

Finally, let's run the container:

$ docker run  helloworld
Hello, world!

Useful Linux commands

User management


To request security privileges of superuser (root):

sudo 



/usr/local/etc/sudoers


.profile file 


There is one global profile file (executed when anyone logs in):

/etc/profile

There are three user-specific bash profile files (executed when current/specific user logs in):

~/.profile
~/.bash_profile
~/.bashrc

If ~/.profile doesn't exist, just create it.

This is the comment at the beginning of ~/.profile:

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

To add en environment variable during the session of a particular user (and also make them available in terminal) append the desired var name and its value to ~/,profile file. Example:

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

We'd need to restart the terminal in order to get these changes visible but to make terminal fetch them in the current session, we can update the current shell session with:

source ~/.profile



File editing


To edit some file, you can use vi editor. Example:

$ vi ~/.profile 

gedit can also be used as graphic editor:

sudo gedit ~/.profile


Package management


apt (Advanced Packaging Tool) - It is not a command itself but a package which contains set of tools which manage installation and removal of other packages.

apt-get

apt-get update - downloads the package lists from the repositories and "updates" them to get information on the newest versions of packages and their dependencies. It will do this for all repositories and PPAs.

http://askubuntu.com/questions/222348/what-does-sudo-apt-get-update-do
apt-cche


add-apt-repository - adds a repository to the list of repositories


To apply latest security updates on Ubuntu:

sudo apt-get update

sudo apt-get -y upgrade


To download a file into some specific directory:

cd /dest_dir
wget https://example.com/archive_file.tar.gz

To unpack the .tar.gz in the current directory use:

tar -xvf archive_file.tar.gz

To unpack the .tar.gz in the specific output directory use:

tar zxvf archive_file.tar.gz output_directory

To install a package/software in Ubuntu, it is usually enough to copy it to /usr/local directory.
To move dir1 to some other location e.g. /usr/local use:

mv new_app /usr/local


To list files in the current directory:

ls

To list all files (including hidden) in the current directory:

ls -a

Hardware management

To verify if you're running a 64-bit system:

uname -m 

x86_64 is the output in case of 64-bit system.

SSH


How to test password for private key?
If id_rsa and id_rsa.pub is a keypair, we can execute (after cd ~/.ssh/):

$ ssh-keygen -y -f id_rsa

...which will prompt us to enter the password. If correct, this will output the public key.

Thursday, 21 March 2019

Golang - Miscellaneous Topics & Useful Links

Go CLI commands

go get

-u is used frequently as it makes get not just to check out missing packages but also to look for updates to existing packages 

Coding Style


https://github.com/golang/go/wiki/CodeReviewComments
https://github.com/Unknwon/go-code-convention/blob/master/en-US/naming_rules.md
https://rakyll.org/style-packages/
Golang - Code organisation with structs, variables and interfaces
Special Packages and Directories in Go

Go naming conventions for const
The standard library uses camel-case, so I advise you do that as well. The first letter is uppercase or lowercase depending on whether you want to export the constant.

Inner/package functions should not be calling panic on error but should return an error (together with a value) and thus allow caller to decide how they want to handle errors and if they want to panic or not.

Function should detect an error and return as soon as possible. The last statement in function body should be returning a valid value and nil as an error.

How to organize Go project?


Go Project Layout
golang-standards/project-layout

How to order packages in import?


Keep them in alphabetical order, with a blank line between:

  • the standard library
  • other libraries 
  • project-specific imports

gofmt: organize imports like eclipse does

Initialization


init functions in Go


Error Handling


Error handling and Go
Custom Errors
Return nil or custom error in Go
When should I use panic vs log.fatalln() in golang?
Part 32: Panic and Recover
Go by Example: Panic

    if err != nil {
        panic(err)
    }

Constants


https://blog.golang.org/constants
Constants in Go established during init

Types


integers



Strings


Printing " (double quote) in GoLang
Use:
  • escape character: fmt.Println("\"") or
  • raw strings: fmt.Println(`"`)
Go by Example: Number Parsing

Enums


Ultimate Visual Guide to Go Enums
Command stringer
Simple enumeration in Golang using Stringer
Assign a string representation to an enum/const (forum thread)
[Golang] Enum and String Representation
Enums in Go

Structs


Go by Example: Structs
Anonymous fields in structs - like object composition
The empty struct

Return pointer to local struct
Go performs pointer escape analysis. If the pointer escapes the local function, the object is allocated on the heap. If it doesn't escape the local function, the compiler is free to allocate it on the stack.

Note that, unlike in C, it's perfectly OK to return the address of a local variable; the storage associated with the variable survives after the function returns.[1]

When possible, the Go compilers will allocate variables that are local to a function in that function’s stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors.[1]

Can you “pin” an object in memory with Go?
An object on which you keep a reference won't move. There is no handle or indirection, and the address you get is permanent. Go's GC is not a compacting GC. It will never move live objects around.

Local variable can escape the local function scope in two cases:
  • variable’s address is returned
  • its address is assigned to a variable in an outer scope


When to return a local instance of struct and when its address?


There are two usual reasons to return a pointer:

  • if we want methods of the struct to generally modify the struct in place (versus needing to create or copy to a new struct when we want to make modifications)
  • if the struct is rather large, a pointer is preferred for efficiency


When to return a pointer?
Constructor returning a pointer

Immutability


Does Go have immutable data structures?

Arrays


GO explicit array initialization
Keyed items in golang array initialization

Slices


https://golang.org/ref/spec#Slices
https://gobyexample.com/slices
https://blog.golang.org/go-slices-usage-and-internals

Channels


Unbuffered 


Example in SO quuestion

Buffered 


A Tour of Go - Channels 
BUFFERED CHANNELS IN GO: TIPS & TRICKS
Buffered Channels In Go — What Are They Good For?
Buffered Channels
Go by Example: Channel Buffering
Different ways to pass channels as arguments in function in go (golang)
https://www.reddit.com/r/golang/comments/7ep1un/golang_channel_is_really_fifo/

Interfaces


Interfaces in Go


Control Flow


for / range


Is there a way to iterate over a range of integers in Golang?
for range [5]int{} {...}

Switch

https://gobyexample.com/switch
https://tour.golang.org/flowcontrol/9
https://github.com/golang/go/wiki/Switch
https://yourbasic.org/golang/switch-statement/


defer

A Tour of Go - defer

panic


When should I use panic vs log.fatalln() in golang?


Functions


Go function type, reusable function signatures
type myFunctionType = func(a, b string) string

Arguments


Verifying arguments



Methods


Methods on structs
You will be able to add methods for a type only if the type is defined in the same package.
Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
Anatomy of methods in Go

Lambdas inside a function

Why doesn't Go allow nested function declarations (functions inside functions)?

OOP - Encapsulation & import


Exported identifiers in Go
What does an underscore in front of an import statement mean in Golang?

dot-import

When you import package prefixed with dot (e.g.: import( . "fmt")), it would be imported in current namespace, so you can omit "fmt" prefix before calling methods. BUT: Don't ever do that; the only time it's useful is in very rare cases involving test files, everywhere else it's a really bad idea.

Concurrency


Go Concurrency Patterns: Pipelines and cancellation
Go Language Patterns - Semaphores
Go’s Extended Concurrency: Semaphores (Part 1)
Essential Go - Limiting concurrency with a semaphore

Unit & Integration Testing



First, something not related specifically to Go but to general software engineering:
TDD and BDD Differences"BDD is just TDD with different words"
Why do some software development companies prefer to use TDD instead of BDD?
How can I do test setup using the testing package in Go
Nice example how to inject unit test checker in an internal method: compare Do() and do() here.
Verbose output prints the names of unit test functions: go test -v
Exploring the landscape of Go testing frameworks
Go With Go(Lang): Features and Testing Frameworks

BDD:
  • ginkgo [Ginkgo] - very active development
  • goconvey
  • goblin - seems that its development has stopped; the last commit in repo was 5 months ago

5 simple tips and tricks for writing unit tests in #golang
Integration Tests in Go
Integration Test With Database in Golang
Separating unit tests and integration tests in Go
Learn Go by writing tests: Structs, methods, interfaces & table driven tests
Testing with golden files in Go
BDD Testing with Ginkgo and GoMock
Clean Go Testing with Ginkgo
done channel 
Using Ginkgo with Gomock
golang/mock
Gomega
Filesystem impact testing
Testing Techniques - Google I/O 2014

Go & DataBases


Scanners and Valuers with Go
How to write unit tests for database calls

Design Patterns in Go


The factory method pattern in Go
Factory patterns in Go (Golang)
A Class Factory in Golang (Google Go)

Go in VSCode

Debugging Go code using VS Code

Misc



Things I Wish Someone Had Told Me About Golang

Random


Package rand
Generating random numbers and strings in Go
https://flaviocopes.com/go-random/
Go by Example: Random Numbers
package uuid

Environment Variables

Pass environment variables from docker to my GoLang.

Friday, 8 March 2019

Running PostgreSQL in Docker inside VirtualBox Ubuntu VM

The last time I used PostgreSQL (and databases in general) was in my Brand Communications days, around 2010-2011. I was then designing and implementing DB support for customer care events coming from VPN clients connected to Apollo server. Today, 9 years later I am coming back to data bases and am witnessing how one software product and overall environment has drastically changed.

Back in 2012, pgAdmin used to be a standalone native desktop application (written in C++ and wxWidgets) and PostgreSQL DB would be running directly on top of the OS. Today, pgAdmin runs in a browser as a web application (written in Python and JavaScript) and connects to a DB instance running more often inside a Docker container in a cloud then on some in-house server...What a nice example of technology evolution! :)

I wanted to catch up with pgAdmin evolution and found the article written by its lead developer where he said:

Aside from it being extremely hard to find C++ developers these days (...) the world is shifting to a web based model these days. Cloud deployments are becoming more widely used, as well as simple instances supplied through hosting providers. Users are getting used to being able to pickup their laptop or a tablet and do whatever they need to do without having to install software – open a browser, read and write email, build a spreadsheet or create a database.

Let's then dive into new paradigms of using PostgreSQL:
  • PostgreSQL image is available in Docker Hub
  • pgAdmin 4 Windows installer can be downloaded from postgresql.org but host has to have some browser installed

Running PostgreSQL in Docker inside VirtualBox Ubuntu image


To pull the official PostgreSQL image from the DockerHub (if not already downloaded) and launch it on your local system, execute the following command:

$ docker run -d -p 5432:5432 --name my-postgres -e POSTGRES_PASSWORD=mysecretpassword postgres

Let's dissect it:

docker run
-d  // runs container in detached mode
-p 5432:5432 // opens port 5432 for incoming connections from external applications
--name my-postgres // sets container name "my-postgres"
-e POSTGRES_PASSWORD=mysecretpassword // sets environment variable
postgres // image name in Docker Hub

To start a terminal in the container use docker exec. From now on, the prompt will show the current user in the container and container ID:

$ sudo docker exec -it my-postgres bash
root@a4a7485fea59:/# ls
bin  boot  dev docker-entrypoint-initdb.d  docker-entrypoint.sh  etc  home  lib  lib64  media mnt  opt  proc root  run  sbin  srv  sys  tmp usr  var
root@a4a7485fea59:/# pwd
/

To launch PostgreSQL interactive terminal use psql.  
To connect to the database as some specific user, use -U <USERNAME>.

root@a4a7485fea59:/# psql -U postgres
psql (11.2 (Debian 11.2-1.pgdg90+1))
Type "help" for help.

To see the help menu, type help:

postgres=# help
You are using psql, the command-line interface to PostgreSQL.
Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit


To see the list of SQL commands for which help is provided, use \h:

postgres=# \h
Available help:
  ABORT                            ALTER TEXT SEARCH TEMPLATE       CREATE PUBLICATION               DROP FUNCTION                    IMPORT FOREIGN SCHEMA
  ALTER AGGREGATE                  ALTER TRIGGER                    CREATE ROLE                      ...

To see help for some particular SQL command type help <COMMAND>:

postgres-# \help abort
Command:     ABORT
Description: abort the current transaction
Syntax:
ABORT [ WORK | TRANSACTION ]

To list all psql commands use \?:

postgres-# \?
General
  \copyright             show PostgreSQL usage and distribution terms
  \crosstabview [COLUMNS] execute query and display results in crosstab
  \errverbose            show most recent error message at maximum verbosity
  \g [FILE] or ;         execute query (and send results to file or |pipe)
  \gdesc                 describe result of query, without executing it
  \gexec                 execute query, then execute each value in its result
  \gset [PREFIX]         execute query and store results in psql variables
  \gx [FILE]             as \g, but forces expanded output mode
  \q                     quit psql
  \watch [SEC]           execute query every SEC seconds

Help
  \? [commands]          show help on backslash commands
  \? options             show help on psql command-line options
  \? variables           show help on special variables
  \h [NAME]              help on syntax of SQL commands, * for all commands

Query Buffer
  \e [FILE] [LINE]       edit the query buffer (or file) with external editor
  \ef [FUNCNAME [LINE]]  edit function definition with external editor
  \ev [VIEWNAME [LINE]]  edit view definition with external editor
  \p                     show the contents of the query buffer
  \r                     reset (clear) the query buffer
  \s [FILE]              display history or save it to file
  \w FILE                write query buffer to file

Input/Output
  \copy ...              perform SQL COPY with data stream to the client host
  \echo [STRING]         write string to standard output
  \i FILE                execute commands from file
  \ir FILE               as \i, but relative to location of current script
  \o [FILE]              send all query results to file or |pipe
  \qecho [STRING]        write string to query output stream (see \o)

Conditional
  \if EXPR               begin conditional block
  \elif EXPR             alternative within current conditional block
  \else                  final alternative within current conditional block
  \endif                 end conditional block

Informational
  (options: S = show system objects, + = additional detail)
  \d[S+]                 list tables, views, and sequences
  \d[S+]  NAME           describe table, view, sequence, or index
  \da[S]  [PATTERN]      list aggregates
  \dA[+]  [PATTERN]      list access methods
  \db[+]  [PATTERN]      list tablespaces
  \dc[S+] [PATTERN]      list conversions
  \dC[+]  [PATTERN]      list casts
  \dd[S]  [PATTERN]      show object descriptions not displayed elsewhere
  \dD[S+] [PATTERN]      list domains
  \ddp    [PATTERN]      list default privileges
  \dE[S+] [PATTERN]      list foreign tables
  \det[+] [PATTERN]      list foreign tables
  \des[+] [PATTERN]      list foreign servers
  \deu[+] [PATTERN]      list user mappings
  \dew[+] [PATTERN]      list foreign-data wrappers
  \df[anptw][S+] [PATRN] list [only agg/normal/procedures/trigger/window] functions
  \dF[+]  [PATTERN]      list text search configurations
  \dFd[+] [PATTERN]      list text search dictionaries
  \dFp[+] [PATTERN]      list text search parsers
  \dFt[+] [PATTERN]      list text search templates
  \dg[S+] [PATTERN]      list roles
  \di[S+] [PATTERN]      list indexes
  \dl                    list large objects, same as \lo_list
  \dL[S+] [PATTERN]      list procedural languages
  \dm[S+] [PATTERN]      list materialized views
  \dn[S+] [PATTERN]      list schemas
  \do[S]  [PATTERN]      list operators
  \dO[S+] [PATTERN]      list collations
  \dp     [PATTERN]      list table, view, and sequence access privileges
  \drds [PATRN1 [PATRN2]] list per-database role settings
  \dRp[+] [PATTERN]      list replication publications
  \dRs[+] [PATTERN]      list replication subscriptions
  \ds[S+] [PATTERN]      list sequences
  \dt[S+] [PATTERN]      list tables
  \dT[S+] [PATTERN]      list data types
  \du[S+] [PATTERN]      list roles
  \dv[S+] [PATTERN]      list views
  \dx[+]  [PATTERN]      list extensions
  \dy     [PATTERN]      list event triggers
  \l[+]   [PATTERN]      list databases
  \sf[+]  FUNCNAME       show a function's definition
  \sv[+]  VIEWNAME       show a view's definition
  \z      [PATTERN]      same as \dp

Formatting
  \a                     toggle between unaligned and aligned output mode
  \C [STRING]            set table title, or unset if none
  \f [STRING]            show or set field separator for unaligned query output
  \H                     toggle HTML output mode (currently off)
  \pset [NAME [VALUE]]   set table output option
                         (NAME := {border|columns|expanded|fieldsep|fieldsep_zero|
                         footer|format|linestyle|null|numericlocale|pager|
                         pager_min_lines|recordsep|recordsep_zero|tableattr|title|
                         tuples_only|unicode_border_linestyle|
                         unicode_column_linestyle|unicode_header_linestyle})
  \t [on|off]            show only rows (currently off)
  \T [STRING]            set HTML <table> tag attributes, or unset if none
  \x [on|off|auto]       toggle expanded output (currently off)

Connection
  \c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo}
                         connect to new database (currently "postgres")
  \conninfo              display information about current connection
  \encoding [ENCODING]   show or set client encoding
  \password [USERNAME]   securely change the password for a user

Operating System
  \cd [DIR]              change the current working directory
  \setenv NAME [VALUE]   set or unset environment variable
  \timing [on|off]       toggle timing of commands (currently off)
  \! [COMMAND]           execute command in shell or start interactive shell

Variables
  \prompt [TEXT] NAME    prompt user to set internal variable
  \set [NAME [VALUE]]    set internal variable, or list all if no parameters
  \unset NAME            unset (delete) internal variable

Large Objects
  \lo_export LOBOID FILE
  \lo_import FILE [COMMENT]
  \lo_list
  \lo_unlink LOBOID      large object operations


To check the PostgreSQL version use:

postgres=# select version();
                                                             version                                                              
----------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 11.2 (Debian 11.2-1.pgdg90+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, 64-bit
(1 row)


To list all databases, use \l:

postgres-# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-----------+----------+----------+------------+------------+-----------------------
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
(3 rows)

To create a new database, execute this SQL command:

postgres=# CREATE DATABASE mytestdb;
CREATE DATABASE

This new database appears in the list of databases:

postgres=# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-----------+----------+----------+------------+------------+-----------------------
 mytestdb  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
(4 rows)


To connect to a database, use \c:

postgres-# \c postgres
You are now connected to database "postgres" as user "postgres".

To list all relations, use \dS:

postgres-# \dS
                        List of relations
   Schema   |              Name               | Type  |  Owner   
------------+---------------------------------+-------+----------
 pg_catalog | pg_aggregate                    | table | postgres
 pg_catalog | pg_am                           | table | postgres
 pg_catalog | pg_amop                         | table | postgres
 pg_catalog | pg_amproc                       | table | postgres
 pg_catalog | pg_attrdef                      | table | postgres
 pg_catalog | pg_attribute                    | table | postgres
 pg_catalog | pg_auth_members                 | table | postgres
 pg_catalog | pg_authid                       | table | postgres
 pg_catalog | pg_available_extension_versions | view  | postgres
 pg_catalog | pg_available_extensions         | view  | postgres
 pg_catalog | pg_cast                         | table | postgres
 pg_catalog | pg_class                        | table | postgres
 pg_catalog | pg_collation                    | table | postgres
 pg_catalog | pg_config                       | view  | postgres
 pg_catalog | pg_constraint                   | table | postgres
 pg_catalog | pg_conversion                   | table | postgres
 pg_catalog | pg_cursors                      | view  | postgres
 pg_catalog | pg_database                     | table | postgres
 pg_catalog | pg_db_role_setting              | table | postgres
 pg_catalog | pg_default_acl                  | table | postgres
 pg_catalog | pg_depend                       | table | postgres
 pg_catalog | pg_description                  | table | postgres
 pg_catalog | pg_enum                         | table | postgres
 pg_catalog | pg_event_trigger                | table | postgres
 pg_catalog | pg_extension                    | table | postgres
 pg_catalog | pg_file_settings                | view  | postgres
 pg_catalog | pg_foreign_data_wrapper         | table | postgres
 pg_catalog | pg_foreign_server               | table | postgres
 pg_catalog | pg_foreign_table                | table | postgres
 pg_catalog | pg_group                        | view  | postgres
 pg_catalog | pg_hba_file_rules               | view  | postgres
 pg_catalog | pg_index                        | table | postgres
 pg_catalog | pg_indexes                      | view  | postgres
 pg_catalog | pg_inherits                     | table | postgres
 pg_catalog | pg_init_privs                   | table | postgres
 pg_catalog | pg_language                     | table | postgres
 pg_catalog | pg_largeobject                  | table | postgres
 pg_catalog | pg_largeobject_metadata         | table | postgres
 pg_catalog | pg_locks                        | view  | postgres
 pg_catalog | pg_matviews                     | view  | postgres
 pg_catalog | pg_namespace                    | table | postgres
 pg_catalog | pg_opclass                      | table | postgres
 pg_catalog | pg_operator                     | table | postgres
 pg_catalog | pg_opfamily                     | table | postgres
 pg_catalog | pg_partitioned_table            | table | postgres
 pg_catalog | pg_pltemplate                   | table | postgres
 pg_catalog | pg_policies                     | view  | postgres
 pg_catalog | pg_policy                       | table | postgres
 pg_catalog | pg_prepared_statements          | view  | postgres
 pg_catalog | pg_prepared_xacts               | view  | postgres
 pg_catalog | pg_proc                         | table | postgres
 pg_catalog | pg_publication                  | table | postgres
 pg_catalog | pg_publication_rel              | table | postgres
 pg_catalog | pg_publication_tables           | view  | postgres
 pg_catalog | pg_range                        | table | postgres
 pg_catalog | pg_replication_origin           | table | postgres
 pg_catalog | pg_replication_origin_status    | view  | postgres
 pg_catalog | pg_replication_slots            | view  | postgres
 pg_catalog | pg_rewrite                      | table | postgres
 pg_catalog | pg_roles                        | view  | postgres
 pg_catalog | pg_rules                        | view  | postgres
 pg_catalog | pg_seclabel                     | table | postgres
 pg_catalog | pg_seclabels                    | view  | postgres
 pg_catalog | pg_sequence                     | table | postgres
 pg_catalog | pg_sequences                    | view  | postgres
 pg_catalog | pg_settings                     | view  | postgres
 pg_catalog | pg_shadow                       | view  | postgres
 pg_catalog | pg_shdepend                     | table | postgres
 pg_catalog | pg_shdescription                | table | postgres
 pg_catalog | pg_shseclabel                   | table | postgres
 pg_catalog | pg_stat_activity                | view  | postgres
 pg_catalog | pg_stat_all_indexes             | view  | postgres
 pg_catalog | pg_stat_all_tables              | view  | postgres
 pg_catalog | pg_stat_archiver                | view  | postgres
 pg_catalog | pg_stat_bgwriter                | view  | postgres
 pg_catalog | pg_stat_database                | view  | postgres
 pg_catalog | pg_stat_database_conflicts      | view  | postgres
 pg_catalog | pg_stat_progress_vacuum         | view  | postgres
 pg_catalog | pg_stat_replication             | view  | postgres
 pg_catalog | pg_stat_ssl                     | view  | postgres
 pg_catalog | pg_stat_subscription            | view  | postgres
 pg_catalog | pg_stat_sys_indexes             | view  | postgres
 pg_catalog | pg_stat_sys_tables              | view  | postgres
 pg_catalog | pg_stat_user_functions          | view  | postgres
 pg_catalog | pg_stat_user_indexes            | view  | postgres
 pg_catalog | pg_stat_user_tables             | view  | postgres
 pg_catalog | pg_stat_wal_receiver            | view  | postgres
 pg_catalog | pg_stat_xact_all_tables         | view  | postgres
 pg_catalog | pg_stat_xact_sys_tables         | view  | postgres
 pg_catalog | pg_stat_xact_user_functions     | view  | postgres
 pg_catalog | pg_stat_xact_user_tables        | view  | postgres
 pg_catalog | pg_statio_all_indexes           | view  | postgres
 pg_catalog | pg_statio_all_sequences         | view  | postgres
 pg_catalog | pg_statio_all_tables            | view  | postgres
 pg_catalog | pg_statio_sys_indexes           | view  | postgres
 pg_catalog | pg_statio_sys_sequences         | view  | postgres
 pg_catalog | pg_statio_sys_tables            | view  | postgres
 pg_catalog | pg_statio_user_indexes          | view  | postgres
 pg_catalog | pg_statio_user_sequences        | view  | postgres
 pg_catalog | pg_statio_user_tables           | view  | postgres
 pg_catalog | pg_statistic                    | table | postgres
 pg_catalog | pg_statistic_ext                | table | postgres
 pg_catalog | pg_stats                        | view  | postgres
 pg_catalog | pg_subscription                 | table | postgres
 pg_catalog | pg_subscription_rel             | table | postgres
 pg_catalog | pg_tables                       | view  | postgres
 pg_catalog | pg_tablespace                   | table | postgres
 pg_catalog | pg_timezone_abbrevs             | view  | postgres
 pg_catalog | pg_timezone_names               | view  | postgres
 pg_catalog | pg_transform                    | table | postgres
 pg_catalog | pg_trigger                      | table | postgres
 pg_catalog | pg_ts_config                    | table | postgres
 pg_catalog | pg_ts_config_map                | table | postgres
 pg_catalog | pg_ts_dict                      | table | postgres
 pg_catalog | pg_ts_parser                    | table | postgres
 pg_catalog | pg_ts_template                  | table | postgres
 pg_catalog | pg_type                         | table | postgres
 pg_catalog | pg_user                         | view  | postgres
 pg_catalog | pg_user_mapping                 | table | postgres
 pg_catalog | pg_user_mappings                | view  | postgres
 pg_catalog | pg_views                        | view  | postgres
(121 rows)


To list tables only use \d:

my_database=# \d
                     List of relations
 Schema    |              Name          | Type  | Owner 
---------- +----------------------------+-------+-------
 public    | customers                  | table | bojan
 public    | audience                   | table | bojan
 public    | campaign                   | table | bojan


To leave psql interactive terminal use \q:

postgres=# \q
root@a4a7485fea59:/# 


If docker container is stopped (by executing docker stop my-postgres,  in some other terminal) prompt of the Ubuntu will appear:

root@a4a7485fea59:/# bojan@bojan-VirtualBox:~$ 

Using pgAdmin on Windows to query PostgreSQL running in Docker on Ubuntu VirtualBox VM


PostgreSQL by default listens on port 5432 and that's why we opened a port on Docker and mapped 5432 onto it. We chose the same port number to be opened on Docker. Now, we need to open that port on our Ubuntu Virtual Machine:


Now we can go back to Windows and after pgAdmin is installed we can add this DB server:


We can name this server as we wish, this name is arbitrary:


We'll use localhost, port 5432, and username and password as we used when we were launching the PostgreSQL:


As soon as we hit "Save" pgAdmin will try to connect to the server and will load all databases in it. We can see our databases here:




TBC...

References:

Connect from local machine to PostgreSQL database in Docker
https://wiki.postgresql.org/wiki/Apt