I will give a high-level overview. Essentially, it is a workflow runner. You can set up "jobs" in a "pipeline" (dependency graph of jobs), and each job is just a bit of yaml. This yaml has individual keys controlling things like running a script, configuring the environment, controlling the docker image executing the job, etc..
These jobs / yaml blobs can be included into other files / projects using another one of these keys, "including" another job/pipeline via configuring the path to the repo & path to the file you want to import. You can override any properties really easily on these includes as well. Anyways, my .gitlab-ci.yml for building a container (any repo containing a top-level Dockerfile works zero-config, non-top-level can be configured) looks like this
include:
- project: 'public-tools/gitlab-extensions'
ref: master
file: '/.gitlab/ci/Docker-build.gitlab-ci.yml'
Then of course that file does the things to run a `docker build` script with secrets passed as build args etc