Some tags in the output from my controller are filtered away
That is behavior Drupal 8 has for the #markup property, as described in Render API overview. It is different from the behavior Drupal 7 had; if you are converting code from Drupal 7, you need to change that part of the code accordingly.


  #markup: Specifies that the array provides HTML markup directly. Unless the markup is very simple, such as an explanation in a paragraph tag, it is normally preferable to use #theme or #type instead, so that the theme can customize the markup. Note that the value is passed through \Drupal\Component\Utility\Xss::filterAdmin(), which strips known XSS vectors while allowing a permissive list of HTML tags that are not XSS vectors. (I.e, &lt;script&gt; and &lt;style&gt; are not allowed.) See \Drupal\Component\Utility\Xss::$adminTags for the list of tags that will be allowed. If your markup needs any of the tags that are not in this whitelist, then you can implement a theme hook and template file and/or an asset library. Aternatively, you can use the render array key #allowed_tags to alter which tags are filtered.


The highlighted part tells you how to solve the filtering of tags.

See also the next part of the documentation.


  #allowed_tags: If #markup is supplied this can be used to change which tags are using to filter the markup. The value should be an array of tags that Xss::filter() would accept. If #plain_text is set this value is ignored.