Run a K3S server in a docker container, and connect a K3S agent in another docker container - kubernetes

I know k3d can do this magically via k3d cluster create myname --token MYTOKEN --agents 1, but I am trying to figure out how to do the most simple version of that 'manually'. I want to create a server something like:
docker run -e K3S_TOKEN=MYTOKEN rancher/k3s:latest server
And connect an agent something like like:
docker run -e K3S_TOKEN=MYTOKEN -e K3S_URL=https://localhost:6443 rancher/k3s:latest agent
Does anyone know what ports need to be forwarded here? How can I set this up? Nearly everything I try, the agent complains about port 6444 already in use, even if I disable as much as possible about the server with any combination of --no-deploy servicelb --disable-agent --no-deploy traefik
Feel free to disable literally everything other than the server and the agent, I'm trying to make this ultra ultra simple, but just butting my head against a wall at the moment. Thanks!

The containers must "see" each other. Docker isolates the networks by default, so "localhost" in your agent container is the agent container itself.
Possible solutions:
Run both containers without network isolation using --net=host, map API port of the server to the host with --port and use the host IP in the agent container or use docker-compose.
A working example for docker-compose is described here: https://www.trion.de/news/2019/08/28/kubernetes-in-docker-mit-k3s.html

Related

kubernetes: Is POD is also like a PC

I see that kubernets uses pod and then in each pod there can be multiple containers.
Example I create a pod with
Container 1: Django server - running at port 8000
Container 2: Reactjs server - running at port 3000
Whereas
I am coming for docker background
So in docker we do
docker run --name django -d -p 8000:8000 some-django
docker run --name reactjs -d -p 3000:3000 some-reactjs
So POD is also like PC with some ubunut os on it
No, a Pod is not like a PC/VM with Ubuntu on it.
There is no intermediate layer between your host and the containers in a pod. The only thing happening here is that the containers in a pod share some resources/namespaces in the host's kernel, and there are mechanisms in your host kernel to "protect" the containers from seeing other containers. Pods are just a mechanism to help you deploy a couple containers that share some resources (like the network namespace) a little easier. Fundamentally they are just linux processes directly on the host.
(one nuanced technicality/caveat on the above statement: Docker and tools like it will sometimes run their own VM and may try to make that invisible to you. For example, Docker Desktop does this. Usually you can ignore this layer, but it is great to know it is there. The answer holds though: That one single VM will host all of your pods/containers and there is not one VM per pod.)

Docker best practice to access host's services

What is best practice to access the host's services within a docker container?
I'd like to access PostgreSQL running on the host within my application which runs in a docker container.
The easiest approach I've found is to use docker container run --net="host" which, based on this answer, behaves as follows:
Such a container will share the network stack with the docker host and from the container point of view, localhost (or 127.0.0.1) will refer to the docker host.
Be aware that any port opened in your docker container would be opened on the docker host. And this without requiring the -p or -P docker run option.
Which does not seem to be best practice since the containers should be isolated from the host.
Other approaches I've found are awking the hosts IP. May this be the way to go?
The best option in this case to treat the host as a remote machine. That way the container will be portable and would not have a strict dependency on network locations when connecting to the database.
In addition to what is mentioned on the drawbacks of using --network=host, this option will tightly couple the container to the host by assuming that the database is found on localhost.
The way to treat the machine as a remote one, is to use standard network constructs such as IP and DNS. Define a new DNS entry for the container that will point to the host where the DB is found using the
--add-host option to docker run.
docker run --add-host db-static:<ip-address-of-host> ...
Then inside the container you connect to the database via db-static

How to make a TCP outgoing connection with Docker container?

My Go application makes TLS connections via tls.Dial() to exchange data.
It works fine when run from the host:
But the outgoing connection doesn't seem to work when the app is run from a Docker container. The app hangs indefinitely.
Note 1: Same behavior with using docker run -p $(docker-machine ip):2500:2500 ...
Note 2: VM doesn't have extra port forwarding settings other than the default settings that came with docker-machine's default VM.
Docker image build with Dockerfile:
FROM golang:latest
RUN mkdir -p "$GOPATH/src/path/to/app"
# Install dependencies
RUN go get github.com/path/to/dep
VOLUME "$GOPATH/src/path/to/app"
EXPOSE 2500
WORKDIR "$GOPATH/src/path/to/app"
CMD ["go", "run", "main.go"]
Host is OS X running docker-machine.
Question
How can I make the TCP outgoing connection to work?
You are either using boot2docker or docker-machine (since you are running docker on OSX). If you are using boot2docker, you have to forward the ports on VirtualBox as well as docker, have a look at this blog post:
https://fogstack.wordpress.com/2014/02/09/docker-on-osx-port-forwarding/
If you are using docker-machine, you have to connect to the docker-machine assigned ip, not localhost, have a look at this post:
https://github.com/docker/machine/issues/710
I see now that you are using docker-machine specifically, so the post about docker-machine should answer your question.
Edit: I misunderstood the question. You are trying to make an outgoing connection on a forwarded port. That is not correct. By default docker can make outgoing connections on any port. The port forwarding is for incoming connections only. Please try again without specifying any ports to forward. My suspicion is that you are trying to make an outgoing connection on the incoming (forwarded) port.
I've just had exactly the same problem. Was unable to connect out at all.
Restarted the container, and suddenly outgoing connections worked fine. It's possible that the container survived an update of docker?
Currently using Docker version 18.09.3, build 774a1f4

Dokku: Expose two ports from an application

I am trying to deploy a Scala based application to dokku, the application runs a http server and a customised sshd server.
The problem I have is it seems that dokku only supports one port for the application.
I need dokku to expose both my applications ports to the web.
In docker this is possible and quite straight forward to do, but when I implement the same technique in the dokku file, I get an error.
Any suggestions on allowing two ports to be accessible?
Since this is, after all, docker, you can use an ambassador...
You will need a line like:
docker run -t -i -link mysql:mysql -name mysql_ambassador -p 3306:3306 ctlc/ambassador
Replacing with your port and mysql with your container name (from docker images)
See https://www.ctl.io/developers/blog/post/deploying-multi-server-docker-apps-with-ambassadors
NOTE: Make sure you docker pull svendowideit/ambassador:latest before...

port redirect to docker containers by hostname

I want to setup serve multiple sites from one server:
1. http://www.example.org => node.js-www (running on port (50000)
2. http://files.example.org => node.js-files (running on port 50001)
Until now I only found out to have docker doing port redirect when using static ips.
Is is actual possible to use docker for port redirection via hostname?
I use a free amazon EC2 insance.
Thanks
Bo
EDIT:
I want to have multiple nodes applications running on the same port but however serving a different hostname.
As far as I'm aware docker does not have such functionality built in, nor it should.
To accomplish what you're trying to do you'd probably need some sort of reverse proxy, so node.js or nginx would do. Bouncy might be a good option: https://github.com/substack/bouncy
There is a great docker project on GitHub called nginx-proxy by jwilder.
This allows you to create a docker container that is doing a reverse-proxy by mapping only his port 80/443 to the host, instead of other containers. Then, all you have to do is for every new web container you create, provide a new environment variable VIRTUAL_HOST=some.domain.com.
An example:
Create a new nginx-proxy container
docker run -d -p 80:80 --net shared_hosting -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
Create a container for each website. For example:
docker run -d -p 80 --net shared_hosting -e VIRTUAL_HOST=hello1.domain.com tutum/hello-world
docker run -d -p 80 --net shared_hosting -e VIRTUAL_HOST=drupal.domain.com drupal
You need to make sure that the hosts you own, configured in DNS to point to the server that runs the docker container. In this example, I will add the to the /etc/hosts file:
echo "127.0.0.1 hello1.domain.com drupal.domain.com" >> /etc/hosts
Navigate to http://hello1.domain.com and then to http://drupal.domain.com, and see that they both use port 80 but give you a different pages.
An important note about this service. As you noticed, I have added --net argument, this is because all containers you want to be a part of a shared hosting (proxy and websites) must be on the same virtual network (this can be defined by the argument --net or --network to the docker run command), especially when you use docker-compose to create dockers, because docker-compose creates its own virtual network, thus makes one container not reachable by another, so make sure the network is explicitly defined in the docker-compose.yml file.
Hope it helps.
I used varnish as a docker container that worked as my reverse proxy
it's on the docker index
https://index.docker.io/u/sysdia/docker-varnish/
I know this is an old question, but ran across it and wanted to point out that there are much cleaner ways to do what was requested. Since you are using AWS, you can have each of your two hostnames pointing at their own load balancer (ELB) in Route53. You could then deploy your container into ECS, for example, listening on both ports. Each of those load balancers can redirect traffic to the appropriate listening port. Now you have accomplished what you want, and if your traffic becomes too heavy or imbalanced, you can easily split the tasks into two different ECS clusters so they can scale independently.