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":


package main
import (
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:


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
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": [
        "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": [
            "Cmd": [
                "#(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": [
            "Cmd": [
            "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": [
        "Metadata": {
            "LastTagTime": "2019-03-22T16:15:30.835954727Z"

Finally, let's run the container:

$ docker run  helloworld
Hello, world!

When I built once natively, on Ubuntu, a similar, small app from scratch, I got the following error when I ran its container:

ERROR: for my_app  Cannot start service carl: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"my_app\": executable file not found in $PATH": unknown

The problem seemed to be related to app being dynamically linked to some of shared libraries on my dev Linux machine so when binary was copied over to empty (scratch) Docker container, binary could not find them so threw such error. I assume this was the reason for such error as solution was to explicitly disable dynamic linking when building my app:

$ CGO_ENABLED=0 go build cmd/main.go 

Indeed, using CGO_ENABLED flag makes a difference. 

Default is dynamic linking:

$ go build cmd/main.go 
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, not stripped

Static linking has to be explicitly set:

$ CGO_ENABLED=0  go build cmd/main.go 
$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

Useful Linux commands

User management

To request security privileges of superuser (root):

$ sudo 


To log in and run the current shell as root use:

user@computer:~$ sudo -i
root@computer:~# whoami
root@computer:~# exit


.profile file 

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


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


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


Chmod permissions (flags) explained

To allow only file user to read and write (but not to execute):

$ chmod 600 filename

Working with directories

To list the content of the directory:


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

ls -a

To list files in some specific directory use:

$ ls target_directory

$ ls /usr/local/go/

To list directories and files in form of a tree install tree package:

$ sudo apt install tree

...and use it as e.g.:

$ tree -I *node*

-I = ignores directories that match given pattern

Working with files

Creating a file

To create a file use touch:

$ touch filename

Getting the information about a file

To see the last couple of lines in the file use command tail:

$ tail myfile

Copying files

cp - copy

File viewing and editing

To simply view the content of some file, use cat:

$ cat filename

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

$ vi ~/.profile 

gedit can also be used as graphic editor:

sudo gedit ~/.profile

Symbolic links


$ sudo ln -s /usr/local/go/bin/go /usr/local/bin/go

Hard links

How to create hardlink of one file in different directories in linux

Working with Environment Variables

To list all environment variables and their values use:

$ env

To set environment variables for the single command:


$ env GOOS=linux GOARCH=amd64 go build cmd/main.go

From the executable's point of view, the same would have been achieved without using env:

$ GOOS=linux GOARCH=amd64 go build cmd/main.go

To set environment variables for the current terminal session:

$ export GOPATH=/mnt/c/dev/go

export is a bash builtin. export key=value is extended syntax and should not be used in portable scripts (i.e. #! /bin/sh)

What's the difference between set, export and env and when should I use each?
What is the difference between set, env, declare and export when setting a variable in a Linux shell?

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 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.


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

Difference Between apt and apt-get Explained

Should I use apt or apt-get?

You might be thinking if you should use apt or apt-get. And as a regular Linux user, my answer is to go with apt.

apt is the command that is being recommended by the Linux distributions. It provides the necessary option to manage the packages. Most important of all, it is easier to use with its fewer but easy to remember options.

I see no reason to stick with apt-get unless you are going to do specific operations that utilize more features of apt-get.


To download a file into some specific directory:

cd /dest_dir

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

A word on Linux directories


/usr/src is meant for source code for the binaries that come with your system's installation. For example, it could contain the source code for your kernel, tools such as ls, passwd, cp, mv etc, which are all installed BY YOUR DISTRIBUTION. If you upgrade your OS from source, all the source code would go here, when you rebuild your system. You DON'T want to put any software that you install BY YOURSELF in here, because they may get overwritten when you upgrade your system. In general, files that are in /, /usr/bin, /usr/sbin, /bin, /sbin etc. have their source code in /usr/src.

The /usr/local directory tree is meant to be used for software that you install by yourself, without using the distribution CD(s). For example, /usr/local/bin, /usr/local/sbin are for the binaries that are installed by you separately, /usr/local/etc is for config files etc. Thus /usr/local/src is for source files that you yourself downloaded.

Example: go (binary distribution) gets installed in /usr/local/go.

If you upgrade your system, files under the /usr tree get overwritten, such as /usr/bin, /usr/sbin, /usr/src etc. However, anything under /usr/local will not be touched. This is why all the software you installed separately should go to /usr/local tree.

Installing Software

How to install software distributed via .deb files?  

$ sudo dpkg -i /path/to/deb/file 
$ sudo apt-get install -f

The latter is necessary in order to fix broken packages (install eventual missing dependencies).

How to install a deb file, by dpkg -i or by apt?

Working with Archive files

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

tar -xvf archive_file.tar.gz

-x = extract
-f (--file) = use archive file
-c (--verbose) = verbose output
-z (--gzip, --gunzip, --ungzip)  = filter the archive through gzip

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

tar zxvf archive_file.tar.gz output_directory


$ tar -C path/to/dest_dir -xzf archive_file.tar

-C (--directory) stands for "Change to directory"

$ tar -C /usr/local -xzf go1.12.1.linux-amd64.tar

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.


How to test password for private key?
If id_rsa and 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.

-y = This option will read a private OpenSSH format file and print an OpenSSH public key to stdout.
-f filename = Specifies the filename of the key file.

Another example:

$ ssh-keygen -t rsa -C ""

-t = Specifies the type of key to create.  The possible values are “dsa”, “ecdsa”, “ed25519”, or “rsa”.
-C comment = Provides a new comment.

To copy the contents of the file to clipboard:

$ xclip -sel clip < ~/.ssh/

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
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

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


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 {

Constants in Go established during init




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


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


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


Does Go have immutable data structures?


GO explicit array initialization
Keyed items in golang array initialization




Example in SO quuestion


A Tour of Go - Channels 
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)


Interfaces in Go

Control Flow

for / range

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



A Tour of Go - defer


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


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


Verifying arguments


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?


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.


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

  • 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
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


Things I Wish Someone Had Told Me About Golang


Package rand
Generating random numbers and strings in Go
Go by Example: Random Numbers
package uuid

Environment Variables

Pass environment variables from docker to my GoLang.

Configuration Files

Best practices for Configuration file in your code
Manage config in Golang to get variables from file and env variables

Useful packages

For unit tests:

Go Modules

Inspired by: Getting started with Go modules

To initialize Go modules in to your application you can run:

$ go mod init /path/to/directory

Example shows that we need to include the path:

root@bc7429fce4a8:~/TestApp# go mod init 
go: cannot determine module path for source directory /root/TestApp (outside GOPATH, no import comments)

root@bc7429fce4a8:~/TestApp# ls

root@bc7429fce4a8:~/TestApp# go mod init /root/TestApp
go: creating new go.mod: module /root/TestApp

root@bc7429fce4a8:~/TestApp# ls
go.mod main.go

root@bc7429fce4a8:~/TestApp# cat go.mod

module /root/TestApp

# go run main.go 
go: finding v1.1.0
go: downloading v1.1.0
Running the TestApp

root@bc7429fce4a8:~/TestApp# go run main.go 
Running the TestApp

# cat go.mod 
module /root/TestApp

require v1.1.0 // indirect

root@bc7429fce4a8:~/TestApp# cat go.sum v1.1.0 h1:gUubB1IEUliFmzjqjhf+bgkg1o6uoFIkRsP3VrhEcx8= v1.1.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y=

If we want to change version of the 3rd party package (go-randomdata in our case) we just need to manually edit the go.mod and set there desired version. go run (or go build) would then apply that version and hashes in go.sum would also change.


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 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  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

To list all psql commands use \?:

postgres-# \?
  \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

  \? [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

  \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)

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

  (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

  \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|
  \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)

  \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

  \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_unlink LOBOID      large object operations

To check the PostgreSQL version use:

postgres=# select 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;

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

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:



Connect from local machine to PostgreSQL database in Docker